zoukankan      html  css  js  c++  java
  • Leetcode上两道很有意思的字符串题(都可以利用重复拼接自身快速解答)

    今天做了Leetcode上一道简单题,一开始我想用两个指针一次循环的方法来做,结果怎么都通过不了,无奈看了答案,答案的方法非常巧妙,通过拼接自身字符串发现潜在的特性。

    这种题目我已经发现了两道,一起来看看这两道题。

    459.重复的子字符串

    给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

    示例 1:

    输入: "abab"

    输出: True

    解释: 可由子字符串 "ab" 重复两次构成。
    示例 2:

    输入: "aba"

    输出: False
    示例 3:

    输入: "abcabcabcabc"

    输出: True

    解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

    这道题的第一想法就是暴力搜,遍历第1到第n/2个子字符串,设从0开始,长度为x,对每个子字符串都遍历剩下的(n/x)-1个字符串,按顺序剩下的每一个字符s[i]都应该和s[i-x]相同,所以再循环一个总字符串的长度即可。时空复杂度较高。

    除了这种暴力解法之外,Leetcode官方提供了一个非常简洁有效的解法(不是KMP,我也不会KMP) 。先给出答案的链接:

    https://leetcode-cn.com/problems/repeated-substring-pattern/solution/zhong-fu-de-zi-zi-fu-chuan-by-leetcode-solution/

    答案通过重复拼接自身构成(s,s)字符串,如果该字符串是由重复的子字符串组成的,那么去头掐尾以后,形成的新字符串(s,s)[1:-1]中一定包含原来的字符串s,读者可以自己试试,这里就不给出证明了,官方答案不仅证明了充分性也证明了必要性。也就是说,我们构造一个(s,s)字符串后,再掐头去尾得到(s,s)[1:-1],在这个字符串中找s,如果找不着,那么说明这个字符串应该不是重复子字符串得到的。代码的逻辑是,找(s,s)[1:]中的s,如果找到的是最后一个末尾的s,那么就不是重复子字符串。

    贴个代码:

    class Solution {
    public:
        bool repeatedSubstringPattern(string s) {
            return (s+s).find(s, 1) != s.size();
        }
    };
    

      巧合的是,我前几天也做了一题——字符串轮转,这道题是一道面试题。同样也是使用拼接自身构造了一个新的字符串再去判断。先看题目:

    面试题01.09 字符串轮转

    字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

    示例1:

    输入:s1 = "waterbottle", s2 = "erbottlewat"
    输出:True
    示例2:

    输入:s1 = "aa", s2 = "aba"
    输出:False
    提示:

    字符串长度在[0, 100000]范围内。
    说明:

    你能只调用一次检查子串的方法吗?

    同样的,当我们拿到这道题,第一思路就是使用一次循环区构造所有的字符串轮转后的结果S1,S2...Sn,同时比较s2是否与之相同,如果有一个相同说明s2是s1旋转得到的。但是题目要求我们只使用一次检查子串的方法。

    做法很简单,如果s2是s1旋转得到的,重复拼接s1得到(s1,s1)中一定包含s2,相当于是把所有旋转的结果都放进了一个字符串中。那么代码就很简单了。

    class Solution {
        public:
        bool isFlipedString(string s1, string s2) {
            if (s1.size() != s2.size()) return false;
            return (s2 + s2).rfind(s1) != -1;
        }
    };
    

      我在这里用的是C++中rfind的方法,当然直接使用find也是可以的。

    总结

    两道题中的字符串,第一个是重复子字符串,第二个是旋转得到的字符串,都具备类似的性质,

    当重复子字符串得到的字符串s拼接自身(s,s)后,即便掐头去尾,s也在(s,s)[1:-1]中,

    当字符串s拼接自身(s,s)后,由它旋转得到的所有字符串s1,s2...Sn,都在(s,s)中,

    所以两道题都利用了这个性质,写出了简洁有效的代码。

  • 相关阅读:
    Response/Request
    每日总结-Day5
    每日总结-Day4
    每日总结-Day3
    每日总结-Day2
    每日总结-Day1
    day6
    Day5
    Day4
    需求分析之软件初设想
  • 原文地址:https://www.cnblogs.com/Hangingter/p/13555244.html
Copyright © 2011-2022 走看看