題目:
You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
題解:
我最開始做的是說把L裡面給的串全排列放起來,看S包含不包含其中之一,包含的話反話其index。但是這個方法TLE了
程式碼:
2 String temp = new String();
3 temp = str[i];
4 str[i] = str[j];
5 str[j] = temp;
6 }
7
8 public static void arrange (String[] L, int st, ArrayList<String> re){
9 if (st == L.length - 1){
10 String temp = new String();
11 for (int i = 0; i < L.length; i ++){
12 temp +=L[i];
13 }
14 re.add(temp);
15 }else{
16 for (int i = st; i < L.length; i ++){
17 swap(L, st, i);
18 arrange(L, st + 1,re);
19 swap(L, st, i);
20 }
21 }
22 return ;
23 }
24 public static ArrayList<Integer> findSubstring(String S, String[] L) {
25 ArrayList<Integer> result = new ArrayList<Integer>();
26 ArrayList<String> possible = new ArrayList<String>();
27 arrange(L,0,possible);
28
29 for(int j= 0; j<possible.size();j++){
30 if(S.contains(possible.get(j)))
31 result.add(S.indexOf(possible.get(j)));
32 }
33
34 return result;
35 }
更好的解法就是一種滑動視窗式的。我是參照了http://blog.csdn.net/linhuanmars/article/details/20342851的寫法,他的寫法目前速度最快。
首先是先把所給的字典利用HashMap建一下,key存word,value存這個word出現的個數。
因為每個單詞長度一樣,外層循序只許迴圈wordLen次,每次指標挪一次,每一次迴圈遍歷整個字串。
內層迴圈每次遍歷一個單詞,把整個S字串遍歷檢查。
需要在每次大迴圈維護一個count,看是不是達到了給的字典字串數量,同時維護一個index,是每個符合條件的字串的起始index,需要存到返回結果中。
為了能夠檢查是不是合格字串,在這裡維護一個curDict的HashMap。
首先檢查一個單詞是不是在原始字典中出現,沒出現的話說明這個單詞肯定不符合標準,index指標指向下一個單詞的起始點,計數器和curDict都要清零。
如果這個單詞在原始字典裡出現過,用更新原始字典的方法更新curDict,如果這個單詞出現的次數沒有超過原始字典裡記錄的次數,那麼count++,如果超過了,就需要挪動指標,並把超過的從curDict刪掉。
最後,如果count達到了L的length,說明找到了一個合格的字串,那麼將index存入返回結果res中,再把index挪到下一個單詞處,更新curDict即可。
code ganker的講解是這樣的:
“
這道題看似比較複雜,其實思路和Longest
Substring Without Repeating Characters差不多。因為那些單詞是定長的,所以本質上和單一個字元一樣。和Longest
Substring Without Repeating Characters的
區別只在於我們需要維護一個字典,然後保證目前的串包含字典裡面的單詞有且僅有一次。思路仍然是維護一個視窗,如果當前單詞在字典中,則繼續移動視窗右
端,否則視窗左端可以跳到字串下一個單詞了。假設源字串的長度為n,字典中單詞的長度為l。因為不是一個字元,所以我們需要對源字串所有長度為l的
子串進行判斷。做法是i從0到l-1個字元開始,得到開始index分別為i,
i+l, i+2*l,
...的長度為l的單詞。這樣就可以保證判斷到所有的滿足條件的串。因為每次掃描的時間複雜度是O(2*n/l)(每個單詞不會被訪問多於兩次,一次是窗
口右端,一次是視窗左端),總共掃描l次(i=0, ...,
l-1),所以總複雜度是O(2*n/l*l)=O(n),是一個線性演算法。空間複雜度是字典的大小,即O(m*l),其中m是字典的單詞數量。
”
程式碼部分我自己稍作了修改,主題思想與code ganker相同。
程式碼如下:
2 ArrayList<Integer> res = new ArrayList<Integer>();
3 if(S==null||L==null||S.length()==0||L.length==0)
4 return res;
5 int wordLen = L[0].length();//same length for each word in dictionary
6
7 //put given dictionary into hashmap with each word's count
8 HashMap<String, Integer> dict = new HashMap<String, Integer>();
9 for(String word: L){
10 if(!dict.containsKey(word))
11 dict.put(word, 1);
12 else
13 dict.put(word, dict.get(word) + 1);
14 }
15
16 for(int i = 0; i < wordLen; i++){
17 int count = 0;
18 int index = i;//index of each startpoint
19 HashMap<String, Integer> curdict = new HashMap<String, Integer>();
20 //till the first letter of last word
21 for(int j = i; j <= S.length() - wordLen; j += wordLen){
22 String curWord = S.substring(j, j + wordLen);
23 //check each word to tell if it existes in give dictionary
24 if(!dict.containsKey(curWord)){
25 curdict.clear();
26 count = 0;
27 index = j + wordLen;
28 }else{
29 //form current dictionary
30 if(!curdict.containsKey(curWord))
31 curdict.put(curWord, 1);
32 else
33 curdict.put(curWord, curdict.get(curWord) + 1);
34
35 //count for current found word and check if it exceed given word count
36 if(curdict.get(curWord) <= dict.get(curWord)){
37 count++;
38 }else{
39 while(curdict.get(curWord) > dict.get(curWord)){
40 String temp = S.substring(index, index + wordLen);
41 curdict.put(temp, curdict.get(temp)-1);
42 index = index + wordLen;//make index move next
43 }
44 }
45
46 //put into res and move index point to nextword
47 //and update current dictionary as well as count num
48 if(count == L.length){
49 res.add(index);
50 String temp = S.substring(index, index + wordLen);
51 curdict.put(temp, curdict.get(temp)-1);
52 index = index + wordLen;
53 count--;
54 }
55 }
56 }//end for j
57 }//end for i
58 return res;
59 }