首页 > 编程语言 >代码训练营 Day9 | 151.翻转字符串里的单词 | 认识KMP算法

代码训练营 Day9 | 151.翻转字符串里的单词 | 认识KMP算法

时间:2024-08-26 11:57:03浏览次数:8  
标签:151 word 前缀 Day9 后缀 fast next KMP string

151.翻转字符串里的单词

  1. 这道题的难度在于如何高效率的处理空格
  2. 对于python来说不能实现空间O(1)的复杂度,不过对于其他语言来说下面思路可以
    1. 使用双指针方法同时指向数组的头部
    2. 循环遍历整个字符串直到数组末尾
    3. 快指针不能为空,因为快指针是要获取字母的,慢指针是用来获取新的字母存放位置的下标
    4. 判断慢指针是否不为0,因为我们的单词可能在第一个单词前面也有空格,我们慢指针只是为了给翻转过后的单词间隔中间添加空格
    5. 用while循环来不断删除多余的空格 (具体思路可以看Day1的帖子移除元素,只不过这里是移除空格思路不变)
  3. 整体思路
    1. 使用reverse函数翻转整个字符串
    2. 移除空格
    3. 每个单独单词再次单独翻转
class Solution(object):
    def reverseWords(self, s):
        """
        :type s: str
        :rtype: str

        remove the empty space
        flip whole string
        flip the word
        """

        def remove_sapce(string):
            string = list(string)
            slow = 0    # get new array letter index
            fast = 0    # get letter

            # iterate the string
            while fast < len(string):
                # check if fast get number
                if string[fast] != " ":
                    # makesure it's not start of the word
                    if slow != 0:
                        # add space between each word
                        string[slow] = " "
                        slow += 1

                    # if there is extra space, or space for first word; remove it
                    while(fast < len(string) and string[fast] != " "):
                        # update the array remove space
                        string[slow] = string[fast]
                        # move both pointer
                        slow += 1
                        fast += 1
                fast += 1
                # return the new string, by using "".join to convert back to string, new index stop at slow

            return "".join(string[:slow])
        
        def reverse_string(string):
            # reverse the whole string
            return string[::-1]
        
        def reverse_word(string):
            # split the word between each space
            words = string.split(" ")
            
            # reverse each word
            return " ".join(word[::-1] for word in words)

        s = remove_sapce(s)
        s = reverse_string(s)
        s = reverse_word(s)

        return s

认识KMP

KMP与解决的问题

1. 文本串:aabaabaaf

2. 模式串:aabaaf

3. 求在文本串里是否出现过模式串

前缀表

1. 上述两个字符串在匹配的过程中当文本串的第二组aab遇到模式串aaf会发现b跟f不匹配了

2. 我们找到f的前面与其相等前缀(这里f的前缀是aa)的后面的那个字母也就是b,再重新开始匹配

前缀与后缀

1. 前缀: 包含首字母 不包含为字母的所有子串都成为前缀

   1. aabaaf: a aa aab aaba aabaa 都为前缀; aabaaf不是前缀因为包含了尾字母

2. 后缀: 只包含尾字母,不包含首字母成为后缀

   1. aabaaf: f af aaf baaf abaaf 都为后缀; aabaaf不是后缀因为包含了首字母

最长相等前后缀

1.  字符    相等前后缀

2.  a           0

3.  aa          1

4.  aab         0

5.  aaba        1

6.  aabaa       2

7.  aabaaf      0

上面 0 1 0 1 2 0 就是我们的前缀表

使用前缀表的匹配过程

1. 前缀表: 0 1 0 1 2 0

2. 我们前缀表最长相等前后缀的值就是我们重新开始匹配元素的下标

   1. 我们跳到前缀的后面,前缀的后面它的下标就是前缀的长度,也就是最长相等前后缀的长度

   2. 因为索引是从0开始所以这里我们跳到下标为2的地方也就是b

   3. 从b这里重新开始匹配   

Next数组

1. 遇到冲突的时候,next数组会告诉我们要回退到那里

2. 把前缀表做一个右移的操作;或者把前缀表整体减1的操作

3. 0 1 0 1 2 0 统一减1之后变成 -1 0 -1 0 1 -1

4. 拿这个这个前缀表去做匹配,统一减去1之后,还会把这个1加回来

缘分不动使用前缀表放入next数组依旧可以实现KMP算法;上面两种是不同形式

伪代码

### Next数组不同的实现方法 伪代码
遇到冲突的位置,我们要向前回退,这个是next数组的核心所在
```c++
// 文本串:aabaabaaf
// 模式串:aabaaf
// 前缀表:0 1 0 1 2 0;     看f前一位这个前缀表值是多少,这个值就对应下标值,我们应该跳到下标值的位置
// 往右移:-1 0 1 0 1 2      遇见冲突时候,直接比较f所对应的前缀表的值,跳到改值的下标位置
// 整体减1:-1 0 -1 0 1 -1   看f前一位,把之前减去的1加上来,再跳到该目标值
// 上面的方式实现方式都可以

// next是next数组,s是模式串
void getNext(next,s){
    //步骤一 初始化; 初始化函数里的变量和next数组
    int j = 0   //j:指向前缀位置; 还代表着i之前包括i字串最长相等前后缀的长度
    next[0] = 0 //next[0]=0,是因为当是只有一个字符的字符串,相同前后缀的最大长度是0
    //i:指向后缀位置; i从1开始这样才能和j进行比较
    for(i=1;i<s.size;i++){
        //步骤二 处理前后缀不相同的情况
        
        // j>0 如果j=0说明j已经回到初始位置; 切记使用while;因为回退不只是回退一次
        while (j > 0 && s[i] != s[j]){
            // 遇到冲突看前一位 前缀表值 并回头过去
            j = nums[j-1]
        }
        
        //步骤三 处理前后缀相同的情况
        if(s[i] == s[j]){
            j++ //还代表着i之前包括i字串最长相等前后缀的长度 由于相同所以需要++ 
        }
        //步骤四 更新next数组值
        next[i] = j;
    }    
}
```

标签:151,word,前缀,Day9,后缀,fast,next,KMP,string
From: https://blog.csdn.net/NeighborKing/article/details/141425054

相关文章

  • day9第四章 字符串part02| 151.翻转字符串里的单词 |卡码网:55.右旋转字符串|28. 实现
    151.翻转字符串里的单词classSolution{publicStringreverseWords(Strings){////删除首尾空格,分割字符串String[]str=s.trim().split("");StringBuildersb=newStringBuilder();////倒序遍历单词列表for(inti......
  • 洛谷 P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two
    [USACO2.4]两只塔姆沃斯牛TheTamworthTwo题目描述两只牛逃跑到了森林里。FarmerJohn开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和John)。追击在10×......
  • 【读书笔记-《30天自制操作系统》-8】Day9
    本篇的主题围绕着内存管理进行展开。首先编写了内存容量获取的程序,接下来详细讲解了内存管理的具体内容,以及两种实现内存管理的方式。1.内存容量获取前面已经实现了访问内存的扩展,能够使用的内存大大增加了。但是不同的应用程序在运行时,对内存的使用会有不同的要求,这就需......
  • CF1514D Cut and Stick 题解
    题目传送门前置知识可持久化线段树解法若区间内不存在绝对众数,直接保持这一段即可。若存在绝对众数,贪心地想肯定要尽可能地把其分开还要限制出其他数使其不成为绝对众数。容易发现设绝对众数出现次数为\(cnt\),取\(cnt-1\)个其他数和绝对众数配对最优。但可能其他数不够\(......
  • KMP-笔记
    tip:以下内容仅本人理解,如有问题,欢迎指出前言(?首先我们要知道KMP是干嘛的KMP是一个字符串匹配算法,相当于AC自动机的弱化版,如果你完全理解了KMP和Trie树的话,那你也离学会AC自动机不远了对于字符串匹配,我们有一个字符串和一个模式串,需要求字符串的子串里有没有这个模式串。......
  • 「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)
    概述为什么大家总觉得KMP难?难的根本就不是这个算法本身。在互联网上你可以见到八十种KMP算法的next数组定义和模式串回滚策略,把一切都懂得特别混乱。很多时候初学者的难点根本不在于这个算法本身,而是它令人痛苦的百花齐放的定义。有的next数组从0下标开始,有的从1开始;有的表......
  • 28:KMP算法
    KMP算法的用途是:在一个字符串中找到某一个字串的位置。时间复杂度是O(N)代码:packagealgorithmbasic.basicsets.class28;publicclassKMP{publicstaticintgetIndexOf(Strings1,Strings2){if(s1==null||s2==null||s1.length()<1||s2.......
  • 【杂乱笔记】Kmp字符串匹配算法
    KMP算法逻辑构建next数组:初始化next数组,用于存储每个位置的最长相同前后缀长度。遍历模式字符串patt如果当前字符与前缀字符匹配,增加前缀长度,并更新next数组。如果不匹配,使用next[prefix\_len-1]回退到上一个可能的前缀长度,继续比较。字符串匹配:初始......
  • 实现strStr() —— KMP算法(包含next数组的优化)
    目录KMP算法KMP算法的应用前缀表最长公共前后缀为什么要使用前缀表如何计算前缀表前缀表和next数组时间复杂度分析例题28.实现strStr构造next数组 使用next数组来做匹配 前缀表统一减一C++代码实现前缀表(不减一)C++代码实现总结 拓展:next数组的优化 KMP算......
  • 代码随想录算法训练营day09|151.翻转字符串里的单词,卡码网:55.右旋转字符串,28.实现 str
    151.翻转字符串里的单词题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/description/暴力removeExtraSpaces:voidremoveExtraSpaces(string&s){for(inti=s.size()-1;i>0;i--){if(s[i]==''&&s[i]=......