題目描述
對於一個非空字符串,判斷其是否可由一個子字符串重復多次組成。字符串只包含小寫字母且長度不超過10000。
樣例1
- 輸入: “abab”
- 輸出: True
- 樣例解釋: 輸入可由”ab”重復兩次組成
樣例 2
- 輸入: “aba”
- 輸出: False
樣例 3
- 輸入: “abcabcabcabc”
- 輸出: True
- 樣例解釋:輸入可由”abc”重復四次組成
解題思路
1. 一個簡單的思路
枚舉子字符串的長度lenSub < len(len為原字符串長度),將原字符串分成多個子字符串,每個子字符串長度為lenSub(由此可見,lenSub整除len),再判斷這些子字符串是否全部相等,若全部相等,則返回True,如果對於所有lenSub均不滿足該條件,則返回False。時間復雜度為O(len*v(len)),其中v(len)為len的因數個數(因為我們只需要對整除len的lenSub進行進一步判斷)。
2. 下面再說一種神奇的方法
由kmp算法中的next數組實現。
-
字符串s的下標從0到n-1,n為字符串長度,記s(i)表示s的第i位字符,s(i,j)表示從s的第i位到第j位的子字符串,若i>j,則s(i,j)=””(空串)。
-
next數組的定義為:next(i)=p,表示p為小於i且滿足s(0 , p) = s(i-p , i)的最大的p,如果不存在這樣的p,則next(i) = -1,顯然next(0) = -1。我們可以用O(n)的時間計算出next數組。假設我們已知next(0),next(1),……,next(i-1) ,現在要求next(i),不妨設next(i-1) = j0,則由next數組定義可知s(0 , j0) = s(i-1-j0 , i-1)。
-
若s(j0+1) = s(i),則結合s(0 , j0) = s(i-1-j0 , i-1)可知s(0 , j0+1) = s(i - (j0+1) , i),由此可知,next(i)=j0+1。
-
若s(j0+1)!=s(i)但s(next(j0)+1)=s(i),記j1=next(j0),則s(j1+1)=s(i),由next數組的定義,s(0 , j1) = s(j0 - j1 , j0) = s(i - 1 - j1 , i - 1),即s(0,j1) = s(i - 1 - j1 , i - 1),由假設s(j1+1) = s(i),則s(0 , j1+1) = s(i - (j1+1) , i),故next(i) = j1+1。
-
同前兩步的分析,如果我們能找到一個k,使得對於所有小於k的k0,s(j(k0)+1)!=s(i),但有s(j(k)+1) = s(i),則由next數組的定義可以得到next(i)=j(k)+1,否則需進一步考慮j(k+1) = next(j(k)),如果我們找不到這樣的k,則next(i)=-1。
-
-
對於字符串s,如果j滿足,0<=j<=n-1,且s(0,j) = s(n-1-j,n-1),令k=n-1-j,若k整除n,不妨設n=mk,則s(0,(m-1)k - 1) = s(k,mk - 1),即s(0,k-1) = s(k,2k-1) = …… = s((m-1)k - 1,mk - 1),即s滿足題設條件。故要判斷s是否為重復子串組成,只需找到滿足上述條件的j,且k整除n,即說明s滿足條件,否則不滿足。
-
利用已算出的next(n-1),令k=n-1-next(n-1),由c可知,若k整除n,且k < n,則s滿足條件,否則不滿足。上述算法的復雜度可證明為O(n)。
參考代碼
參考代碼給出了利用next數組求解的代碼。
public class Solution { public boolean repeatedSubstringPattern(String s) { int l = s.length(); int[] next = new int[l]; next[0] = -1; int i, j = -1; for (i = 1; i < l; i++) { while (j >= 0 && s.charAt(i) != s.charAt(j + 1)) { j = next[j]; } if (s.charAt(i) == s.charAt(j + 1)) { j++; } next[i] = j; } int lenSub = l - 1 - next[l - 1]; return lenSub != l && l % lenSub ==0; } }
面試官角度分析
這道題的第一種解法比較簡單,考察窮舉和字符串處理的能力,給出第一種方法並正確分析時間復雜度基本可以達到hire;如果面試者對KMP算法有了解,可以給出第二種next數組的算法可以達到strong hire。