LeetCode题目笔记——459. 重复的子字符串,python从700ms到60ms

文章目录

    • 题目描述
    • 题目难度——简单
    • 方法一:模拟
      • 代码Python
    • 方法一优化
    • 方法二:一行代码解决
      • 代码
    • 总结

题目描述

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:

输入: s = “abab” 输出: true 解释: 可由子串 “ab” 重复两次构成。 示例 2:

输入: s = “aba” 输出: false 示例 3:

输入: s = “abcabcabcabc” 输出: true 解释: 可由子串 “abc” 重复四次构成。 (或子串 “abcabc”
重复两次构成。)

提示:

1 <= s.length <= 104 s 由小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/repeated-substring-pattern
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目难度——简单

方法一:模拟

  由子串重复构成它本身的话,最好情况下是偶数长度时,由一半的字符重复2次就能构成,对奇数个的话,要么是长度为3的子串构成,要么是长度为1,重复n次。那么我们就可以从长度为1的子字符串开始,逐渐到一半的字符,每次对子字符串进行多次复制,判断与原字符串是否相同。

代码Python

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        res = False
        length = len(s)
        for i in range(1, length // 2 + 1):
            subs = s[:i]
            for j in range(2, length // i + 1):
                if subs * j == s:
                    res = True
                    break 
            if res:
                break
        return res

LeetCode题目笔记——459. 重复的子字符串,python从700ms到60ms_第1张图片
  这个代码太low了,700多ms,甚至都不配上图。不过看代码雀实很慢,有好多无用的切片,字符串拼接等。接下来进行优化。

方法一优化

  根据前面的分析,我们知道一个字符串如果可以由子串重复多次来构成的话,那么他们之间的长度肯定是一个倍数关系,也就是说原字符串s的长度N,和子字符串subs的长度SN,存在N=SN×M的关系,这个M就是重复的次数。那么我们就可以像分解质因数那样,将N分解为多个SN×M的组合。以题目给的例子abcabcabcabc为例,它的长度为12。我们可以把它分解为:

12=1x12: a重复12次:aaaaaa…aa
12=2x6: ab重复6次:abab…ab 或者abcabc重复两次
12=3x4: abc重复4次 或者abca重复3次

  这样来看,我们就只需要从1开始,判断N对其取余能不能得到0,即能不能分解为两个数N、M相乘,然后再以子字串重复M次和原字符串s比对,就能得到答案。

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        res = False
        length = len(s)
        for a in range(1, length // 2 + 1):
            subs = s[:a]
            b = length / a
            if length % b != 0:
                continue
            if subs * int(b) == s:
                res = True
                break
        return res

LeetCode题目笔记——459. 重复的子字符串,python从700ms到60ms_第2张图片
  可以看到和原来相比,快了7倍,好歹能上官方的图了。但是呢,还是很慢,只超过了55%。还可以继续优化。字符串切片也是比较耗时的一个操作,上面的代码里我们在每次循环的第一步都是直接切片,而好多情况下b是不满足要求的,所以我们可以把切片放到判断b成功之后进行。

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        res = False
        length = len(s)
        for a in range(1, length // 2 + 1):
            b = length / a
            if length % b != 0:
                continue
            subs = s[:a]
            if subs * int(b) == s:
                res = True
                break
        return res

LeetCode题目笔记——459. 重复的子字符串,python从700ms到60ms_第3张图片
  又快了40ms,说明优化的还不错。

方法二:一行代码解决

  看了一下排在我前面的,几乎都是这个方法,就是直接判断s是不是s+s的子串,且起始位置不是0或n。具体的证明过程就不详说了,有一点复杂,感兴趣的读者可以去看官方题解。

代码

class Solution:
    def repeatedSubstringPattern(self, s: str) -> bool:
        return (s + s).find(s, 1) != len(s)

'''
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/repeated-substring-pattern/solution/zhong-fu-de-zi-zi-fu-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
'''
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

/*作者:LeetCode-Solution
链接:https://leetcode.cn/problems/repeated-substring-pattern/solution/zhong-fu-de-zi-zi-fu-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

总结

  时间是O(N),空间上,用到了额外的字符串来判断,所以是O(N)。第二种方法需要理论上的证明,有点复杂。

你可能感兴趣的:(LeetCode,leetcode,算法)