代码随想录刷题记录 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.

串2 a b c a b c a b
Next -1 0 0 0 1 2 3 4

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

串1 …… a b c a b c a X (i) ……
串2 a b c a b c a b (j=7)
串1 …… a b c a b c a X (i) ……
串2 a b c a b (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是这样的。

a b c a b e
Next -1 0 0 0 1 2
a b c a b c
Next -1 0 0 0 1 2

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

你可能感兴趣的:(刷题,leetcode,算法,c++)