代码随想录自刷4:字符串

55 阅读2分钟

344. 反转字符串

344. 反转字符串

思路:没什么特别的思路,要求不能用额外的数组,则可以用两个指针进行操作,不会^的可以用一个char暂存,在进行交换

public void reverseString(char[] s) {
        int start=0;
        int end=s.length-1;
        while(start<end){
            s[start]^=s[end];
            s[end]^=s[start];
            s[start]^=s[end];
            start++;
            end--;
        }
    }

[541. 反转字符串 II]

541. 反转字符串 II

思路:这题难在原题目的解释,其实就是当前k个字符串进行交换,后k个字符串不动,是一轮。这样一轮一轮循环下去,最后不满k个字符串则剩余全部交换。

  • 所以i每次移动都是加上2k,到达新位置
public String reverseStr(String s, int k) {
        char[] chr=s.toCharArray();
        for(int i=0;i<chr.length;i+=k*2){
            //要进行交换
            int start=i;
            int end=Math.min(i+k,chr.length)-1;
            converse(chr,start,end);
        }
        return new String(chr);
    }
    public void converse(char[] chars,int s,int e){
        while(s<e){
            chars[s]^=chars[e];
            chars[e]^=chars[s];
            chars[s]^=chars[e];
            s++;
            e--;
        }
    }

[剑指 Offer 05. 替换空格]

剑指 Offer 05. 替换空格

思路:要修改字符串就要想到StringBuilder

public String replaceSpace(String s) {
        StringBuilder sb=new StringBuilder();
        for(char ch : s.toCharArray()){
            if(ch==' '){
                sb.append("%20");
            }else
                sb.append(ch);
        }
        return sb.toString();
    }

151. 反转字符串中的单词

151. 反转字符串中的单词

思路:整体先反转一次,就达到所有单词的位置被反转了(不管单词内容),再针对每个单词内部进行反转,这样单词内部内容就正序了!

  • 创建三个方法:
    • 去除多余空格
    • 反转范围内的字符串
    • 反转每个单词内容
      • 注意要用start作为判断,否则最后一个单词不会被反转到(如果用end作为判断的话,end走到sb.length()不符合条件跳出,于是最后一个单词没反转)
 public String reverseWords(String s) {
        StringBuilder sb=removeSpace(s);
        //整个反转
        reverse(sb,0,sb.length()-1);
        //反转每个单词
        reverseString(sb);
        return sb.toString();

    }
    public StringBuilder removeSpace(String s){
        //去除多余空格
        int start=0;
        while(s.charAt(start)==' ')
            start++;
        int end=s.length()-1;
        while(s.charAt(end)==' ')
            end--;
        StringBuilder sb = new StringBuilder();
        while(start<=end){
            char c = s.charAt(start);
                            //去除中间多余空格
            if(c!=' ' || sb.charAt(sb.length()-1)!=' ')
                sb.append(c);
            start++;
        }
        return sb;
    }
    //反转给定范围内的字符串
    public void reverse(StringBuilder sb,int start,int end){
        while(start<end){
            char tmp=sb.charAt(start);
            sb.setCharAt(start,sb.charAt(end));
            sb.setCharAt(end,tmp);
            start++;
            end--;
        }
    }
    //反转每个单词
    public void reverseString(StringBuilder sb){
        int start=0;
        int end=start+1;
        //要用start作为判断,否则最后一个单词不会被反转到(end走到最后了不符合条件跳出)
        while(start<sb.length()){
            while(end<sb.length() && sb.charAt(end)!=' ')
                end++;
            reverse(sb,start,end-1);
            start=end+1;
            end=start+1;
        }
    }

剑指 Offer 58 - II. 左旋转字符串

剑指 Offer 58 - II. 左旋转字符串

思路:先反转0~n-1的字符串,再反转n~最后的字符串,最后整体反转!

原来:abcdefg

各自反转:ba|gfedc

整体反转:cdefg|ab
public String reverseLeftWords(String s, int n) {
        StringBuilder sb=new StringBuilder(s);
        converse(sb,0,n-1);
        converse(sb,n,sb.length()-1);
        converse(sb,0,sb.length()-1);
        return sb.toString();
    }
    public void converse(StringBuilder sb,int start,int end){
        if(start>end)
            return ;
        while(start<end){
            char ch=sb.charAt(start);
            sb.setCharAt(start,sb.charAt(end));
            sb.setCharAt(end,ch);
            start++;
            end--;
        }
    }

28. 找出字符串中第一个匹配项的下标(KMP)

28. 找出字符串中第一个匹配项的下标

思路:这题是KMP经典题目。首先要了解KMP是什么:当前出现字符串不匹配时,可以记录部分之前匹配好的内容,这样下次继续匹配时不需要从头再次开始,而是根据之前已经匹配好的继续开始即可

KMP主要用在匹配字符串,KMP有一个重要组成就是前缀表(一个next数组),它是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。

前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀

  • 前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串
  • 后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

其他具体KMP介绍看代码随想录这篇笔记写的很清楚还有视频可以看28. 实现 strStr()

public int strStr(String haystack, String needle) {
        if(needle==null || needle.length()==0)
            return -1;
        int[] next=new int[needle.length()];
        getNext(next,needle);
        int j=0;    //j 指向模式串needle起始位置,i指向文本串haystack起始位置
        for(int i=0;i<haystack.length();i++){
            while(j>0 && haystack.charAt(i)!=needle.charAt(j))
                j=next[j-1];    //当前不匹配,j就要从next数组里寻找下一个匹配的位置
            if(haystack.charAt(i)==needle.charAt(j)){
                j++;    //匹配,向后移动
            }
            if(j==needle.length())  //j来到模式串末尾表示都匹配完了!
                return i-needle.length()+1; //下标从0开始所以+1
        }
        return -1;
    }
    
    private void getNext(int[] next,String s){
        int j=0;    //j指向前缀末尾位置,i指向后缀末尾位置
        next[0]=0;
        for(int i=1;i<s.length();i++){
            //处理前后缀不相同的情况
            if(j>0 && s.charAt(i)!=s.charAt(j)){   
                //进行回退,找j前一个元素在next数组里的值,就是它要回退到的位置
                j=next[j-1];    
            }
            //处理前后缀相同的情况
            if(s.charAt(i)==s.charAt(j)){
                j++;    //j向后移动
            }
            next[i]=j;  //next[i]要记录此时相同前后缀的长度
        }
    }

459. 重复的子字符串

459. 重复的子字符串

思路:一样用KMP next数组最后一个值,可以得到下标i之前(包括i)有多大长度的相同前缀后缀,最大长度相同前缀后缀就可以想成是多个重复子串的组合。

public boolean repeatedSubstringPattern(String s) {
        if(s.equals(""))
            return false;
        int[] next=new int[s.length()];
        getNext(next,s);
        int len=s.length();
        int x=next[len-1];
        //len-x得到剩余的字符串(可能是最小重复zi chuan,长度除以剩余字符串的余数为0表示都是由重复字符串所组成没有其他额外字符串
        if(x!=0 && len%(len-x)==0)
            return true;
        return false;
    }
    private void getNext(int[] next,String s){
        int j=0;
        next[0]=0;
        for(int i=1;i<s.length();i++){
            while(j>0 && s.charAt(j)!=s.charAt(i)){
                j=next[j-1];
            }
            if(s.charAt(j)==s.charAt(i))   
                j++;
            next[i]=j;
        }
        
    }

思路:

思路:

思路:

思路: