2021.01.05 较大分组的位置

今日题目:在一个由小写字母构成的字符串 s 中,包含由一些连续的相同字符所构成的分组。
例如,在字符串 s = “abbxxxxzyy” 中,就含有 “a”, “bb”, “xxxx”, “z” 和 “yy” 这样的一些分组。
分组可以用区间 [start, end] 表示,其中 start 和 end 分别表示该分组的起始和终止位置的下标。上例中的 “xxxx” 分组用区间表示为 [3,6] 。
我们称所有包含大于或等于三个连续字符的分组为 较大分组 。
找到每一个 较大分组 的区间,按起始位置下标递增顺序排序后,返回结果。
image.png

  • 思路:

法一:遍历字符串,将目前的一位字符与下一位字符进行比较,若相等,则length+1,并将指针移到下一位,与下一位的下一位进行比较;直到出现遍历结束或者两个字符不相等的情况。若出现两个字符不相等的情况,则判断此时length是否大于2,若是大于2,则符合条件,则将此轮的开始位置begin与此时字符所对应的下标存入列表中。
感觉自己讲不清楚,还是画个图8:打勾的地方即为符合条件的即length > 2的组。
image.png
法二:剑指中(基于C)提到可以将字符串转为字符数组,然后先遍历一遍字符数组,然后统计出空格的数量,就可以计算出替换空格后字符数组的长度。然后从后往前遍历进行字符的移动或替换。示意图如下:
image.png
但是java中字符串的性质与C中的不太一致,因此法二的思路是正确的,但是否同等适用于java就不一定了

同理的题:
有两个排序的数组A1和 A2,内存在Al的末尾有足够多的空余空间容纳A2。请实现一个函数,把A2中的所有数字插入A1中,并且所有的数字是排序的。
和前面的例题一样,很多人首先想到的办法是在A1中从头到尾复制数字,但这样就会出现多次复制一个数字的情况。更好的办法是从尾到头比较A1和A2中的数字,并把较大的数字复制到A1中的合适位置。

注:在合并两个数组(包括字符串)时,如果从前往后复制每个数字(或字符)则需要重复移动数字(或字符)多次,那么我们可以考虑从后往前复制,这样就能减少移动的次数,从而提高效率。

  • 自己的菜鸡代码:
  1. class Solution {
  2. public List<List<Integer>> largeGroupPositions(String s) {
  3. // 暴力法解决
  4. int begin,length;
  5. int s_len = s.length();
  6. List<List<Integer>> record = new ArrayList<>();
  7. for(int i = 0; i<s_len-1; i++){
  8. length = 1;
  9. begin = i;
  10. while(i<s_len-1 && s.charAt(i) == s.charAt(i+1)){
  11. ++length;
  12. ++i;
  13. }
  14. if(length>2 && i<s.length()){
  15. List<Integer> data = new ArrayList<>();
  16. data.add(begin);
  17. data.add(i);
  18. record.add(data);
  19. }
  20. }
  21. return record;
  22. }
  23. }

运行结果:
image.png

2021.01.05 替换空格

今日题目:请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
限制:0 <= s 的长度 <= 10000
image.png

  • 思路:暴力法解决。利用StringBuilder类型的变量temp作为临时变量,逐个遍历目标字符串中的字符,若为非空格字符,则直接用append(s.charAt(i)) 的方法拼接两个字符串;若为空格字符,则用append(“%20”),使“%20”代替空格。
  • 自己的菜鸡代码:
    1. class Solution {
    2. public String replaceSpace(String s) {
    3. // 暴力美学
    4. StringBuilder temp = new StringBuilder();
    5. for(int i = 0; i < s.length(); i++){
    6. if(s.charAt(i) == ' '){
    7. temp.append("%20");
    8. }else{
    9. temp.append(s.charAt(i));
    10. }
    11. }
    12. return temp.toString();
    13. }
    14. }
    运行结果:
    image.png

2021.01.25 第一次只出现一次的字符(哈希表的使用)

今日题目:在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
image.png
限制:0 <= s 的长度 <= 50000

  • 思路:
  • 法一:(有序哈希表)遍历字符串,以字符为key,出现的次数为value保存在哈希表中,但是普通HashMap不是按存入顺序进行排序的,所以采用LinkedHashMap,这样子增加了时间和空间的开销。

    此处补充一下LinkedHashMap的一些特性:LinkedHashMap和HashMap的区别在于它们的基本数据结构上,看一下LinkedHashMap的基本数据结构,也就是Entry: 列一下Entry里面有的一些属性吧: 1、K key 2、V value 3、Entry next 4、int hash 5、Entry before 6、Entry after 其中前面四个,也就是红色部分是从HashMap.Entry中继承过来的;后面两个,也就是蓝色部分是LinkedHashMap独有的。不要搞错了next和before、After,next是用于维护HashMap指定table位置上连接的Entry的顺序的,before、After是用于维护Entry插入的先后顺序的。

  1. private static class Entry<K,V> extends HashMap.Entry<K,V> {
  2. // These fields comprise the doubly linked list used for iteration.
  3. Entry<K,V> before, after;
  4. Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
  5. super(hash, key, value, next);
  6. }
  7. ...
  8. }
  • 法二:可以直接使用普通哈希表,像上述方法记录出现次数,然后再遍历一遍字符串,逐个查找出现一次的字符。

    同样的思想,同上述法二,但是哈希表中的键值对为,当表中无该字符,则存入true值,当表中有该字符,则存入false值。最后再遍历一遍字符串,查找第一个值为true的值。

  • 法三:桶思想。因为题目中很清楚地写了范围为小写字母,所以可以直接用容量为26的数组来统计每个字符出现的次数,最后再遍历一遍字符串,返回第一个只出现一次的字符。

  • 自己的菜鸡代码: ```java // 法一 class Solution { public char firstUniqChar(String s) {

    1. LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
    2. for(int i = 0; i < s.length(); i++){
    3. char c = s.charAt(i);
    4. if(map.get(c) == null){
    5. map.put(c, 1);
    6. }else{
    7. int value = map.get(c);
    8. map.put(c, ++value);
    9. }
    10. }
    11. for(Map.Entry<Character,Integer> entry : map.entrySet()){
    12. if(entry.getValue() == 1){
    13. return entry.getKey();
    14. }
    15. }
    16. return ' ';

    } }

// 法二 class Solution { public char firstUniqChar(String s) {

  1. HashMap<Character,Integer> map = new HashMap<>();
  2. char[] ch = s.toCharArray();
  3. for(char c : ch){
  4. if(!map.containsKey(c)){
  5. map.put(c, 1);
  6. continue;
  7. }
  8. int value = map.get(c);
  9. map.put(c, ++value);
  10. }
  11. for(char c : ch){
  12. if(map.get(c) == 1){
  13. return c;
  14. }
  15. }
  16. return ' ';
  17. }

}

// 大佬改进版法二 class Solution { public char firstUniqChar(String s) { HashMap map = new HashMap<>(); char[] ch = s.toCharArray(); for(char c : ch){ map.put(c, !map.containsKey(c)); }

  1. for(char c : ch){
  2. if(map.get(c)){
  3. return c;
  4. }
  5. }
  6. return ' ';
  7. }

}

// 大佬改进版法一 class Solution { public char firstUniqChar(String s) { LinkedHashMap map = new LinkedHashMap<>(); char[] ch = s.toCharArray(); for(char c : ch){ map.put(c, !map.containsKey(c)); }

  1. for(Map.Entry<Character,Boolean> entry : map.entrySet()){
  2. if(entry.getValue()){
  3. return entry.getKey();
  4. }
  5. }
  6. return ' ';
  7. }

}

  1. - 运行结果:
  2. 自己版本的法一、法二<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611734351535-9ebcb258-5954-4b32-856f-5581bb9efc74.png#align=left&display=inline&height=233&margin=%5Bobject%20Object%5D&name=image.png&originHeight=465&originWidth=620&size=29705&status=done&style=none&width=310)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611739455517-833c876d-811a-4ce9-8a20-1a53b53b01b3.png#align=left&display=inline&height=230&margin=%5Bobject%20Object%5D&name=image.png&originHeight=460&originWidth=635&size=29993&status=done&style=none&width=317.5)<br />大佬版本的法一、法二<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611752340510-e59212d5-b4a7-4da8-9bd4-7e2cdeafc4e5.png#align=left&display=inline&height=221&margin=%5Bobject%20Object%5D&name=image.png&originHeight=441&originWidth=630&size=29367&status=done&style=none&width=315)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611750605564-fc61ce69-d06d-4c46-a4b1-330a3aecf0ab.png#align=left&display=inline&height=228&margin=%5Bobject%20Object%5D&name=image.png&originHeight=456&originWidth=646&size=30762&status=done&style=none&width=323)<br />法三:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611755111339-683784b3-d760-4c58-b7f4-a56a1ea45b1f.png#align=left&display=inline&height=228&margin=%5Bobject%20Object%5D&name=image.png&originHeight=455&originWidth=627&size=29679&status=done&style=none&width=313.5)
  3. <a name="EHEpQ"></a>
  4. ### 2021.01.29 左旋转字符串
  5. 今日题目:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611907176827-4189f772-7c48-45ca-ba4b-b7b4a3b09630.png#align=left&display=inline&height=102&margin=%5Bobject%20Object%5D&name=image.png&originHeight=118&originWidth=266&size=3548&status=done&style=none&width=229)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611907196517-bbb43bb8-8926-4e8c-b85f-896e14380a79.png#align=left&display=inline&height=106&margin=%5Bobject%20Object%5D&name=image.png&originHeight=114&originWidth=294&size=3825&status=done&style=none&width=274)<br />限制:1 <= k < s.length <= 10000
  6. - 思路:利用StringBuilder类作为临时字符串用于拼接。时间复杂度:空间复杂度
  7. - 自己的菜鸡代码:
  8. ```java
  9. class Solution {
  10. public String reverseLeftWords(String s, int n) {
  11. StringBuilder temp = new StringBuilder(s.substring(n, s.length()));
  12. temp.append(s.substring(0,n));
  13. return temp.toString();
  14. }
  15. }
  • 运行结果:

image.png