Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.
Example 1:
Input: "abab" Output: True Explanation: It's the substring "ab" twice.
Example 2:
Input: "aba" Output: False
Example 3:
Input: "abcabcabcabc" Output: True Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)
這道題給了我們一個字符串,問其是否能拆成n個重復的子串。那么既然能拆分成多個子串,那么每個子串的長度肯定不能大於原字符串長度的一半,那么我們可以從原字符串長度的一半遍歷到1,如果當前長度能被總長度整除,說明可以分成若干個子字符串,我們將這些子字符串拼接起來看跟原字符串是否相等。 如果拆完了都不相等,返回false。
解法一:
class Solution { public: bool repeatedSubstringPattern(string str) { int n = str.size(); for (int i = n / 2; i >= 1; --i) { if (n % i == 0) { int c = n / i; string t = ""; for (int j = 0; j < c; ++j) { t += str.substr(0, i); } if (t == str) return true; } } return false; } };
下面這種方法是參考的網上的這個帖子,原作者說是用的KMP算法,LeetCode之前也有一道應用KMP算法來解的題Shortest Palindrome,但是感覺那道題才是KMP算法。這道題也稱為KMP算法感覺怪怪的(關於KMP的詳細介紹請參見從頭到尾徹底理解KMP,也可以看博主自己寫的一篇KMP Algorithm 字符串匹配算法KMP小結),KMP算法中的next數組是找當前位置的最大相同前綴后綴的個數,而這道題維護的一位數組dp[i]表示,到位置i-1為止的重復字符串的字符個數,不包括被重復的那個字符串,什么意思呢,我們舉個例子,比如"abcabc"的dp數組為[0 0 0 0 1 2 3],dp數組長度要比原字符串長度多一個。那么我們看最后一個位置數字為3,就表示重復的字符串的字符數有3個。如果是"abcabcabc",那么dp數組為[0 0 0 0 1 2 3 4 5 6],我們發現最后一個數字為6,那么表示重復的字符串為“abcabc”,有6個字符。那么怎么通過最后一個數字來知道原字符串是否由重復的子字符串組成的呢,首先當然是最后一個數字不能為0,而且還要滿足dp[n] % (n - dp[n]) == 0才行,因為n - dp[n]是一個子字符串的長度,那么重復字符串的長度和肯定是一個子字符串的整數倍,參見代碼如下:
解法二:
class Solution { public: bool repeatedSubstringPattern(string str) { int i = 1, j = 0, n = str.size(); vector<int> dp(n + 1, 0); while (i < n) { if (str[i] == str[j]) dp[++i] = ++j; else if (j == 0) ++i; else j = dp[j]; } return dp[n] && (dp[n] % (n - dp[n]) == 0); } };
類似題目:
參考資料:
https://discuss.leetcode.com/topic/68498/one-line-with-regex/2
https://discuss.leetcode.com/topic/67992/java-simple-solution-with-explanation