LeetCode 笔记系列七 Substring with Concatenation of All Words

题目: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).

这道题想了蛮久,主要是coding过程中老是出一些边界的错误。第一眼看到,立(zi)马(zuo)想(cong)到(ming)的解法是不是可以用bit位来表示L中的各个key呀,不同的key代表不同的位,然后通过扫描S,通过与操作确定各个bit位是不是在长度为L的substring中。结果写了一会发现问题是,L中有可能有相等的字符串哦。。。那在搜索S的时候就悲剧了不是。

一个折中的方法是,对每个key在L中的,保存一个list,例如有L=["foo","bar","foo"],那我们做这样一个hash哇:

foo: 0->1

bar: 2

然后在搜索S的时候顺次检查一个bitset。代码如下:

解法一:

 1 public static ArrayList<Integer> findSubstring2(String S, String[] L) {
 2         int lengthPerKey = L[0].length();
 3         int numberOfKeys = L.length;
 4         BitSet bitSet = new BitSet(numberOfKeys);
 5         HashMap<String, ArrayList<Integer>> map = new HashMap<String, ArrayList<Integer>>();
 6         ArrayList<Integer> result = new ArrayList<Integer>();
 7         int k = 0;
 8         for(String str : L){
 9             if(!map.containsKey(str)){
10                 ArrayList<Integer> list = new ArrayList<Integer>();
11                 list.add(k++);
12                 map.put(str, list);
13             }else {
14                 map.get(str).add(k++);
15             }
16         }
17         
18         for(int i = 0; i <= S.length() - numberOfKeys*lengthPerKey; i++){
19             bitSet.clear();
20             int j = 0;
21             int st = i;
22             for(j = 0; j < numberOfKeys;j++){
23                 if(S.length() - st < (numberOfKeys - j)*lengthPerKey) break;
24                 ArrayList<Integer> list = map.get(S.substring(st, st + lengthPerKey));
25                 if(list == null)break;
26                 k = 0;
27                 while(k < list.size() && bitSet.get(list.get(k))) k++;
28                 if(k < list.size())
29                     bitSet.set(list.get(k));
30                 else break;
31                 st += lengthPerKey;
32             }
33             if(bitSet.cardinality() == numberOfKeys) {
34                 result.add(i);
35             }
36         }
37         return result;
38     }
View Code

不幸的是,大集合超时了。我去。。。

仔细想想,非要用bitset么?特别是扫描的inner loop,还要遍历hash的value(list)。完全可以用一个计数代替么。不用遍历list,对于重复出现的,我们search S的时候,只是减去计数1.

解法二:

 1 public static ArrayList<Integer> findSubstring3(String S, String[] L) {
 2         int lengthPerKey = L[0].length();
 3         int numberOfKeys = L.length;
 4         HashMap<String, Integer> map = new HashMap<String, Integer>();
 5         ArrayList<Integer> result = new ArrayList<Integer>();
 6         for(String str : L){
 7             if(!map.containsKey(str)){
 8                 map.put(str, 1);
 9             }else {
10                 map.put(str, map.get(str) + 1);
11             }
12         }
13         
14         for(int i = 0; i <= S.length() - numberOfKeys*lengthPerKey; i++){
15             int j = 0;
16             int st = i;
17             HashMap<String, Integer> wordsCount = new HashMap<String, Integer>(map);
18             for(j = 0; j < numberOfKeys;j++){
19                 if(S.length() - st < (numberOfKeys - j)*lengthPerKey) break;
20                 String sub = S.substring(st,st+lengthPerKey);
21                 if(wordsCount.containsKey(sub)){
22                     int times = wordsCount.get(sub);
23                     if(times == 1) wordsCount.remove(sub);
24                     else wordsCount.put(sub, times - 1);
25                 }else break;
26                 st += lengthPerKey;
27             }
28             if(j == numberOfKeys){
29                 result.add(i);
30             }
31         }
32         return result;
33     }
View Code

例如L=["foo","bar","foo"],我们的hash是这样的:

foo: 2

bar: 1

然后对S中每一个固定长度的substring做计数。

总结:

1.如果你用了超过3个(包括3个)复杂数据结构,应该思考是不是自己想多了

2.想多了会了你。

3.不要装b,先理解问题再想解法而不是为了用某个算法。

 

 

 

posted on 2013-07-06 11:29  lichen782  阅读(1860)  评论(1编辑  收藏  举报