LeetCode 30. Substring with Concatenation of All Words

原题链接在这里: https://leetcode.com/problems/substring-with-concatenation-of-all-words/description/

题目: 

ou are given a string s and an array of strings words of the same length. Return all starting indices of substring(s) in s that is a concatenation of each word in words exactly once, in any order, and without any intervening characters.

You can return the answer in any order.

Example 1:

Input: s = "barfoothefoobarman", words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoo" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:

Input: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
Output: []

Example 3:

Input: s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
Output: [6,9,12] 

Constraints:

  • 1 <= s.length <= 104
  • s consists of lower-case English letters.
  • 1 <= words.length <= 5000
  • 1 <= words[i].length <= 30
  • words[i] consists of lower-case English letters.

题解:

类似Longest Substring Without Repeating Characters, 这类快慢指针维护substring的方法在Minimum Window Substring里有总结.

Have a word to frequency map to record words.

For index i from start of s to s.length() - wordLen * wordsCount + 1, check if we could have window contains all the words.

Main a visited map in the window. For each candidate = s.substring(i + j * wordLen, i + (j + 1) * wordLen), if it is not in the words, break.

If it is in the words, put into visited map. If the frequency is even higher than in words, then window contains more candidates than words, break.

If j count reach wordsCount, then we find a good window. Add index to the result.

Note: index range is till s.length() - wordLen * wordsCount.

e.g. words contains 4 words, each length 1. s length is 8. Then index is 4, there are still 4 characters, thus it could be a good window.

i < s.length() - wordLen * wordsCount + 1. Don't forget about +1.

Time Complexity: O(n * count). n = s.length(). count = words.length.

Space: O(count).

AC Java:

 1 class Solution {
 2     public List<Integer> findSubstring(String s, String[] words) {
 3         List<Integer> res = new ArrayList<>();
 4         if(s == null || s.length() == 0 || words == null || words.length == 0){
 5             return res;
 6         }
 7         
 8         HashMap<String, Integer> wordToFreq = new HashMap<>();
 9         for(String word : words){
10             wordToFreq.put(word, wordToFreq.getOrDefault(word, 0) + 1);
11         }
12         
13         int n = s.length();
14         int count = words.length;
15         int len = words[0].length();
16         for(int i = 0; i < n - len * count + 1; i++){
17             HashMap<String, Integer> visited = new HashMap<>();
18             int j = 0;
19             while(j < count){
20                 String can = s.substring(i + j * len, i + (j + 1) * len);
21                 if(wordToFreq.containsKey(can)){
22                     visited.put(can, visited.getOrDefault(can, 0) + 1);
23                     if(visited.get(can) > wordToFreq.get(can)){
24                         break;
25                     }
26                     j++;
27                 }else{
28                     break;
29                 }
30             }
31             
32             if(j == count){
33                 res.add(i);
34             }
35         }
36         
37         return res;
38     }
39 }

需要先生成global map计算words中每个word 的frequency. 快慢指针围成的window里也有个小的map计算map中出现在words的word, 当出现一个就count++.

当count是words数目和时就找到了一个结果.

检查当前词是否是words里的词时外层循环是多种取词方法,以例子来说就是分成:

|bar|foo|the|foo|bar|man

b|arf|oot|hef|oob|arm|an

ba|rfo|oth|efo|oba|rma|n

Note: s.substring(startIndex, endIndex) 其中的endIndex必须比s string本身长度小.

Time Complexity: O(n * len). n = s.length(). len = words[0].length().

Space: O(words.length). 

AC Java:

 1 class Solution {
 2     public List<Integer> findSubstring(String s, String[] words) {
 3         List<Integer> res = new ArrayList<Integer>();
 4         if(words == null || words.length == 0 || s == null || s.length() == 0){
 5             return res;
 6         }
 7         
 8         // 计算原有word frequency
 9         HashMap<String, Integer> hm = new HashMap<String, Integer>();
10         for(String word : words){
11             hm.put(word, hm.getOrDefault(word, 0)+1);
12         }
13         
14         int wordLen = words[0].length();
15         int count = 0;
16         int walker = 0;
17         
18         // 从等长word长度的开始到结尾挨个试,不需要再往后,因为那已经被长度开始里面的runner下一跳包括
19         for(int i = 0; i<wordLen; i++){
20             walker = i;
21             count = 0;
22             HashMap<String, Integer> windowHm = new HashMap<String, Integer>();
23             int max = s.length()-wordLen+1;
24             
25             for(int runner = walker; runner < max; runner += wordLen){
26                 String cur = s.substring(runner, runner+wordLen);
27                 if(hm.containsKey(cur)){
28                     // cur string在words中
29                     windowHm.put(cur, windowHm.getOrDefault(cur, 0)+1);
30                     if(windowHm.get(cur) <= hm.get(cur)){
31                         count++;
32                     }else{
33                         // cur这个词在window里出现的次数 多余 原来words中的次数
34                         while(windowHm.get(cur) > hm.get(cur)){
35                             String walkerStr = s.substring(walker, walker+wordLen);
36                             windowHm.put(walkerStr, windowHm.get(walkerStr)-1);
37                             if(windowHm.get(walkerStr) < hm.get(walkerStr)){
38                                 count--;
39                             }
40                             walker += wordLen;
41                         }
42                     }
43                     
44                     // 全部覆盖,向前移动walker
45                     if(count == words.length){
46                         res.add(walker);
47                         String walkerStr = s.substring(walker, walker+wordLen);
48                         windowHm.put(walkerStr, windowHm.get(walkerStr)-1);
49                         count--;
50                         walker += wordLen;
51                     }
52                 }else{
53                     // cur 不在words中
54                     windowHm.clear();
55                     count = 0;
56                     walker = runner+wordLen;
57                 }
58             }
59         }
60         
61         return res;
62     }
63 }

 

posted @ 2015-08-12 10:14  Dylan_Java_NYC  阅读(262)  评论(0编辑  收藏  举报