• 代码随想录刷题记录 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;
    
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    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位是否相同。

  • 相关阅读:
    社交网络分析的 R 基础:(六)绘图操作
    Mysql_Note7
    dpdk 多线程 gdb + master
    回收站删除的文件怎么恢复,2个方法汇总助您快速解决
    SpringBoot(一、快速入门)
    Mit6.006-lecture05-Linear-Sorting
    excel导出标准化
    通用代码生成器应用场景四,跨编程语言翻译
    【python】遇上COS美图怎么办?当然是大胆冲呀~
    Java和JavaScript是一样的技术吗?
  • 原文地址:https://blog.csdn.net/weixin_43720526/article/details/126765594