代码随想录刷题记录 4 - 字符串

记一下刷到哪了,推:代码随想录

4.字符串

难度题目类型 ( 空间 + 时间复杂度 )
简单344.反转字符串遍历 O(1)+O(n)
简单541. 反转字符串II遍历 O(1)+O(n)
简单05.替换空格遍历 O(n)+O(n)
中等151.翻转字符串里的单词遍历 O(n)+O(n)
简单58-II.左旋转字符串计数 O(k)+O(n+m)
中等28. 实现 strStr()(√)KMP O(m)+O(n+m)
简单459. 重复的子字符串(√)枚举 O(1)+O(nlogn)

总结:28 和 459 比较有意思,可以顺便复习KMP,其他的没必要做。

28. 实现 strStr()

字符串匹配,经典 KMP。复习一下(每次都重新学,但是感觉顺畅了很多)。
串1,串2, 在字符串1中找到串2的位置。
KMP的精髓在于,如何利用前面已经匹配上的结果,匹配失败时,不从头匹配,而是从一个特别地位置继续匹配,这取决于串2的结构,所以对匹配串2做处理。
Next [ j ] 表示,当串1中位置 i 和 串2中位置 j 匹配失败时,下一个应该匹配 i 和 串2中的谁。
所以,Next [ j ] 就是,串2中,0 到 j-1,前缀和后缀的最大匹配
举个例子,串2是 abcabcab,当匹配到最后一个b失败时,说明当前的串1是abcabcaX,再匹配第二个b.

串2abcabcab
Next-10001234

j 本来已经到了7,匹配失败后, j=4.

串1……abcabcaX (i)……
串2abcabcab (j=7)
串1……abcabcaX (i)……
串2abcab (j=4)

贴一份板子:

class Solution {
public:
    void getNext(string needle, int Next[]) {
        int j = 0, k = -1;
        int len = needle.size();
        Next[0] = -1;
        while(j < len-1) {
            if(k == -1 || needle[j] == needle[k]) {
                j++;
                k++;
                Next[j] = k;
            }
            else k = Next[k];// 从前面某个地方再尝试匹配
        }
        return;
    }
    int strStr(string haystack, string needle) {
        if(needle.size() == 0) return 0;
        int len1 = haystack.size(), len2 = needle.size();
        int Next[10005] = {0};
        getNext(needle, Next);
        //for(int i = 0; i < len2; i++) cout << Next[i] << " ";
        int i = 0, j = 0;
        while(i < len1 && j < len2) {

            if(j == -1 || haystack[i] == needle[j] ) {
                i++; j++;
            }
            else{
                j = Next[j];
            }
            if(j == len2) {
                return i-j;
            }       
            //cout << i << " " <<  j << endl;      
        }
        return -1;

    }
};

459. 重复的子字符串

1.枚举

偶数次重复一定可以从正中间劈开。
奇数次重复需要枚举重复长度,为小于等于 len/2 的因子。
len/2是个好剪枝。
一般O(nlogn)的复杂度就可以了。

2.KMP

如果满足题意,那么应该从第二个循环节开始,一直往后累加。
所以最后一个位置,如果 s[len-1] == s[next[len-1]],并且,len % ( len-(1+ next[len-1]) ) == 0,就是满足题意的字符串。
否则不是。
len-(1+ next[len-1]) 就是循环节。
有必要说明一下,根据上面的KMP程序,得出的next是这样的。

abcabe
Next-100012
abcabc
Next-100012

因为next是不包含当前位的,是当前位匹配失败后,计算的是前面的最长缀,所以无法区分上面两种情况。
所以需要再加一个判断,看看最后位和它的next位是否相同。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值