代码随想录之字符串(力扣题号)KMP算法

541 反转字符串2

在这里插入图片描述
按照题目的意思来写就行,但是写了非常久,因为在string的基础上改是改不了的,string不是可以编辑的字符,要先转换成char[]数组,再在数组上改动,最后把char[]变为String

class Solution {
    public String reverseStr(String s, int k) {
        char[] arr = s.toCharArray();      
        for(int i=0;i<arr.length;i=i+2*k){
            // if(i+k<arr.length){
            //     rever(arr,i,i+k);
            // }else{
            //     rever(arr,i,arr.length); //剩下不足k的全部翻转
            // }
            rever(arr,i,Math.min(i+k,arr.length));
        }
        return new String(arr);
    }
    public void rever(char[] s, int begin, int end){
        for(int i=begin,j=end-1;i<=j;i++,j--){//记得是从begin开始end结束
            char t = s[i];
            s[i] = s[j];
            s[j] = t;
        }
    }
}

剑指offer 05 替换空格

在这里插入图片描述
这题太简单,两分钟解决

class Solution {
    public String replaceSpace(String s) {
        //37-39
        StringBuffer res = new StringBuffer();
        for(int i = 0;i<s.length();i++){
            if(s.charAt(i)==' ') res.append("%20");
            else res.append(s.charAt(i));
        }
        return res.toString();

    }
}

看了题解可以用双指针在原地进行修改,先把长度扩充到加入%20后的长度,然后从右往左赋值,这样的好处是不用额外的数组。但是这样的方法用Java行不通,因为java的string不能原地扩充,还是要用StringBuffer之后用双指针,那就失去了双指针的意义。

151 反转字符串中的单词

class Solution {
    public String reverseWords(String s) {
        //50-09
        String[] strs = s.split(" +");
        StringBuffer res = new StringBuffer();
        for(int i=strs.length-1;i>=0;i--){
            res.append(strs[i]);
            if(i>0) res.append(" ");
        }
        if(strs[0].equals("")){ //而不是" "!! split方法无法去掉开头的空格,如果开头有空格,strs[0]为"",而不是" "
            res.deleteCharAt(res.length()-1);
        } 
        return res.toString();

    }
}

下次直接用trim()函数去掉首尾的多个空格

class Solution {
    public String reverseWords(String s) {
        //50-09
        //先去掉首尾的多个空格
        s= s.trim();
        String[] strs = s.split(" +");
        StringBuffer res = new StringBuffer();
        for(int i=strs.length-1;i>=0;i--){
            res.append(strs[i]);
            if(i>0) res.append(" ");
        }
        return res.toString();

    }
}

28 找出字符串中第一个匹配的字符

在这里插入图片描述
暴力匹配很简单时间复杂度是O(mn)

class Solution {
    public int strStr(String haystack, String needle) {
        //32-47
        int res = -1;
        for(int i=0;i<haystack.length();i++){
            if(haystack.charAt(i)==needle.charAt(0)&&i+needle.length()<=haystack.length()){//第一个相同才会继续判断
                int f = 1;
                int start = i;
                for(int j=0;j<needle.length();){
                    if(haystack.charAt(start++)!=needle.charAt(j++)){//不同就跳出
                        f = 0;
                        break;
                    }
                }
                if(f==1){
                    return i;
                }
            }            
        }
        return res;
    }
}

最出名的字符串匹配算法是KMP算法,时间复杂度为O(m+n),关键在于维护一个Next数组,表示前缀和后缀相同的最长长度。

学了KMP算法,还是得把代码记一下
https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

class Solution {
    //前缀表(不减一)Java实现
    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) return 0;
        int[] next = new int[needle.length()];
        getNext(next, needle);

        int j = 0;
        for (int i = 0; i < haystack.length(); i++) {
            while (j > 0 && needle.charAt(j) != haystack.charAt(i)) 
                j = next[j - 1];
            if (needle.charAt(j) == haystack.charAt(i)) 
                j++;
            if (j == needle.length()) 
                return i - needle.length() + 1;
        }
        return -1;
    }    
    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; 
        }
    }
}

459 重复的子字符串


很明显这题也是用KMP算法,但是怎么转换呢,我一开始想的是next数组在最后一位的值如果大于等于长度的一半即可,提交了两次错误,因为并不一定是偶数个重复子串,还是看了题解的判断方法

  1. 最后一位的next不为0,否则连重复都没有
  2. 总长度是 剩余长度的整数倍,即
s.length()%(s.length()-next[s.length()-1])==0
class Solution {
    public boolean repeatedSubstringPattern(String s) {
        //50 求next数组 只要最后一位的next>=s.length()/2 即可
        int j = 0;
        int[] next = new int[s.length()];
        next[0] = 0;
       // if(s.length()==1) return true; 是false
        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;
        }
        //System.out.println(Math.ceil((double)3/2));要强制类型转换
        if(next[s.length()-1]!=0&&s.length()%(s.length()-next[s.length()-1])==0) return true;
        else return false;

    }
}

时间和空间复杂度都是O(N)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值