代码随想录第九天:字符串与KMP算法

Day9…救命啊!!!

151.翻转字符串里的单词

给定一个字符串,逐个翻转字符串中的每个单词。

示例 1:

输入: "the sky is blue"

输出: "blue is sky the"

用python的split是很简单的

class Solution(object):
    def reverseWords(self, s):
        slist = s.split()
        for i in range(len(slist)//2):
            slist[i], slist[len(slist)-1-i] = slist[len(slist)-1-i], slist[i]
        return ' '.join(slist)

好的,再次简单地有点罪恶,那来按照“不要使用辅助空间,空间复杂度要求为O(1)”来写一下吧,python字符串是不可变的,那就转化成数组实验一下,下面这个方法其实很慢,但是当作代码练习了

class Solution(object):
    def reverseWords(self, s):
        s = list(s)
        size = len(s)
        #去除空格,双指针
        fast, slow =0, 0 
        while fast < size:
            if s[fast] != " ":
                s[slow] = s[fast]
                slow += 1
                fast += 1
            elif fast>0 and s[fast-1] != " ":
                s[slow] = s[fast]
                slow += 1
                fast += 1
            else:
                fast += 1
        #检查末尾是否有空格影响
        if s[-1]==" ":
            s = s[:slow-1]
        else:
            s= s[:slow]

        #翻转
        def reverse(s,left,right):
            for i in range((right-left+1)//2):
                s[left+i], s[right-i] = s[right-i], s[left+i]

        n = len(s)
        reverse(s,0,n-1)
        i,start = 0,0
        #翻转每个单词
        while i < n:
            while i+1 < n and s[i+1] != " ":
                i += 1
            reverse(s,start,i)
            i += 1
            start = i + 1
        
        return "".join(s)

右旋字符串

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。

例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。

#Python简易版
n = int(input())
s = input()
print(s[-n:]+s[:-n])

为了凸显这道题的练习价值,同样还是把字符串转化为可变化的数组进行练习

相当于在原字符前面面开辟了长度与s相同的空间,然后通过两个指针把后面的字符交换到前面去

n = int(input())
s = input()

s = [""] * len(s)+list(s)
old = len(s)-1
new = len(s)//2-1

for i in range(n):
    s[old], s[new] = s[new], s[old]
    old -= 1
    new -= 1

print("".join(s))

好的,题解中的思路也很巧妙,需要学习

通过 整体倒叙,把两段子串顺序颠倒,两个段子串里的的字符在倒叙一把,负负得正,这样就不影响子串里面字符的顺序了。

28. 找出字符串中第一个匹配项的下标(KMP算法)

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。

帮你把KMP算法学个通透!(理论篇)_哔哩哔哩_bilibili

到KMP算法了,看了一下视频,理解总结一下要点.

(1)kmp算法解决什么问题?

对于给定的模式串,在文本串中找出第一个与模式串相同的子串。

(2)用什么方法?

使用前缀表。利用已经匹配的子串中可能存在的相同的前后缀,充分利用已经匹配的部分,减少需要遍历的次数。

(3)核心方法思路

前缀是指只包含首字母,不包含尾字母的子串;后缀反之。核心是求最长的相等前后缀。前缀表存储的是,对于模式串来说,“匹配到目前为止,匹配上的子串中最长相等前后缀的长度”。【注意,前后缀的读取顺序都是从左往右读】使用前缀表减少匹配次数,相当于“合理跳步”。

(4)为什么这样的跳步是合理的?(重点理解)

Kmp算法的扫描过程中,文本串的指针是不回退的,全靠模式串上的指针后退移动匹配文本串内容。

用视频例子举例:模式串到下标5发现模式串f与文本串对不上,那么就向前一个(下标4)看看已经匹配上的前子串中,最长相同前后缀是多少。在next数组中读取到是2,意思是说,在已经匹配好的内容中,前2个字母(aa)和后2个字母(aa)相同。站在文本串的视角,相当于说,我aaf匹配不上,但是我aa(相同前后缀)匹配上了呀,那我只要看下一个是不是b(匹配上aab)就行了,没必要从最开头的a开始匹配。

(5)如何计算next数组(计算模式串的前缀表)

理解中参考了前缀函数与 KMP 算法 - OI Wiki (oi-wiki.org)这一篇,写的很好,最有提示性的一句是

“当移动到下一个位置时,前缀函数的值要么增加一,要么维持不变,要么减少。”

(这里用前缀表不减一的思路理解,即next默认值为0)

定义两个指针i和j,j指向前缀末尾位置,i指向后缀末尾位置。

每一次i的循环相当于在找s[0:n]的子串s[0:i]的最长相同前后缀长度next[i](代码最后一行赋值也就是next[i] = j;)

参考一下代码来理解:

    void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 0;
        for(int i = 1; i < s.size(); i++) {
            while (j > 0 && s[i] != s[j]) { //前后缀末尾不相同时
// j要保证大于0,因为下面有取j-1作为数组下标的操作
                j = next[j - 1]; // 注意这里,是要找前一位的对应的回退位置了
            }
            if (s[i] == s[j]) {//前后缀末尾相同时
                j++;
            }
            next[i] = j;
        }
    }

python代码如下,最主要是理解j=next[j-1]这个关键代码,一个类似于递归倒退的过程 

class Solution:
    def getNext(self, next: List[int], s: str) -> None:
        j = 0
        next[0] = 0
        for i in range(1, len(s)):
            while j > 0 and s[i] != s[j]:
                j = next[j - 1]
            if s[i] == s[j]:
                j += 1
            next[i] = j
    
    def strStr(self, haystack: str, needle: str) -> int:
        if len(needle) == 0:
            return 0
        next = [0] * len(needle)
        self.getNext(next, needle)
        j = 0
        for i in range(len(haystack)):
            while j > 0 and haystack[i] != needle[j]:
                j = next[j - 1]
            if haystack[i] == needle[j]:
                j += 1
            if j == len(needle):
                return i - len(needle) + 1
        return -1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值