字符串:KMP算法,反转字符串

目录

KMP算法:字符串查找,寻找匹配的字符串,避免重复匹配,增加时间复杂度

前缀表:求得的最长相同前后缀的长度就是对应前缀表的元素,一次遍历实现

字符不匹配,回退 = 指针移到前一字符具有相应前后缀位置后,直到字符匹配或len=0

字符匹配,在当前相同前后缀长度上+1

给当前元素的前缀表赋值

 巧妙运用  反转字符串(反转由双指针实现)(减少空间复杂度)


KMP算法:字符串查找,寻找匹配的字符串,避免重复匹配,增加时间复杂度

28. 实现 strStr():请你在 haystack 字符串中找出 needle 字符串出现的第一个位置  O(m+n)

前缀表:求得的最长相同前后缀的长度就是对应前缀表的元素,一次遍历实现

  • 字符不匹配,回退 = 指针移到前一字符具有相应前后缀位置后,直到字符匹配或len=0

  • 字符匹配,在当前相同前后缀长度上+1

  • 给当前元素的前缀表赋值

class Solution {
    public int strStr(String haystack, String needle) {
        int j = 0, i = 0;
        int[] next = buildNext(needle);
        while(i < haystack.length()){//i一直后移
            while(j > 0 && haystack.charAt(i) != needle.charAt(j)){
                j = next[j-1];//回退到前一个可以匹配的字符
            }
            if(haystack.charAt(i) == needle.charAt(j)){
                j++;//匹配则指针后移
            }
            if(j == needle.length()){//匹配成功
                return i-j+1;
            }
             i++;
        } 
        return -1;
    }
    public int[] buildNext(String s){
        int[] next = new int[s.length()];
        int pre_len = 0;//最长的相等的真前缀与真后缀的长度
        for(int i = 1; i < s.length(); i++){
            while(pre_len > 0 && s.charAt(pre_len) != s.charAt(i)){
                pre_len = next[pre_len-1]; //字符不匹配,就一直回退
                //存在a-1,就要判断a>0,防止角标越界
            }
            //最大相等长度要么比前一个字符多一个pre_len++,要么跳转到pre_len=0
            if(s.charAt(pre_len) == s.charAt(i)){
                pre_len++;//比前一个匹配字符多一个
            }
            next[i] = pre_len;//
        }
        return next;
    }
}

459. 重复的子字符串:给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。eg:s = "abcabcabc"

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        int n =  s.length();
        int[] next = new int[n];
        int len = 0;
        
        for(int i = 1; i < n; i++){
            while(len > 0 && s.charAt(i) != s.charAt(len)){
                len = next[len-1];
            }
            if(s.charAt(i) == s.charAt(len)){
                len++;
            }
            next[i] = len;
        }
        if((next[n-1] > 0)&&(next[n-1] % (s.length()-next[n-1]) == 0)){
            return true;
        }
        return false;
    }
}

 巧妙运用  反转字符串(反转由双指针实现)(减少空间复杂度)

剑指 Offer 58 - II. 左旋转字符串:把字符串前面的若干个字符转移到字符串的尾部

//方法一:借助额外空间
// class Solution {
//     public String reverseLeftWords(String s, int n) {
//         char[] so = s.toCharArray();
//         char[] sl = new char[n];
//         for(int i = 0; i<n; i++){
//             sl[i] = so[i];
//         }
//         for(int i = n; i<s.length(); i++){
//             so[i-n] = so[i];
//         }
//         for(int i = 0; i<n; i++){
//             so[i+s.length()-n] = sl[i];
//         }
       
//         return  new String(so);
//     }
// }

//方法二:借助反转
class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] so = s.toCharArray();
        reverse(so,0,n-1);
        reverse(so,n,s.length()-1);
        reverse(so,0,s.length()-1);
        return new String(so);
    }
    public void reverse(char[] s,int l, int r){
        while(l<r){
            char t = s[l];
            s[l] = s[r];
            s[r] = t;
            l++;
            r--;
        }
    }
}

151. 颠倒字符串中的单词:颠倒后的字符串中不能存在多余空格、前导空格和尾随空格。

输入:s = "  hello world  "
输出:"world hello"
class Solution {
    public String reverseWords(String s) {
        char[] sinit = s.toCharArray();
        char[] res = new char[s.length()];
        int count = 0, resi = 0, si = s.length()-1;
        while(si >= 0){
            while(si >= 0 && sinit[si] == ' '){
                si--;
            }
            int index = si;//单词右侧
            while(si >= 0 && sinit[si] != ' '){
                si--;//单词左侧
            }
            for(int i = si+1; i<=index; i++){
                res[count++] = sinit[i];
                if(i == index && si != -1 ){
                    res[count++] = ' ';
                }
            }
        }
        if(res[count-1] == ' '){
            count--;
        }
        return new String(res,0,count);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值