|
1 | 1 | class Solution {
|
2 | 2 | public List<Integer> findSubstring(String s, String[] words) {
|
3 |
| - if (s.length() == 0 || words.length == 0) { |
4 |
| - return new ArrayList<>(); |
5 |
| - } |
6 |
| - Map<String, Integer> wordFreqMap = new HashMap<>(); |
| 3 | + int numberOfWords = words.length; |
| 4 | + int singleWordLength = words[0].length(); |
| 5 | + int totalSubstringLength = singleWordLength * numberOfWords; |
| 6 | + Map<String, Integer> wordCount = new HashMap<>(); |
7 | 7 | for (String word : words) {
|
8 |
| - wordFreqMap.put(word, wordFreqMap.getOrDefault(word, 0) + 1); |
| 8 | + wordCount.put(word, wordCount.getOrDefault(word, 0) + 1); |
9 | 9 | }
|
10 |
| - int stringLength = s.length(); |
11 |
| - int wordCount = words.length; |
12 |
| - int singleWordLength = words[0].length(); |
13 |
| - List<Integer> indices = new ArrayList<>(); |
14 |
| - for (int i = 0; i + singleWordLength * wordCount <= stringLength; i++) { |
15 |
| - if (match(s, i, singleWordLength, wordFreqMap, wordCount)) { |
16 |
| - indices.add(i); |
17 |
| - } |
| 10 | + List<Integer> result = new ArrayList<>(); |
| 11 | + for (int i = 0; i < singleWordLength; i++) { |
| 12 | + slidingWindow(i, s, result, singleWordLength, totalSubstringLength, wordCount, numberOfWords); |
18 | 13 | }
|
19 |
| - return indices; |
| 14 | + return result; |
20 | 15 | }
|
21 |
| - |
22 |
| - private boolean match(String s, int start, int singleWordLength, Map<String, Integer> wordFreqMap, int wordCount) { |
23 |
| - Map<String, Integer> currFreqMap = new HashMap<>(); |
24 |
| - for (int i = 0; i < wordCount; i++) { |
25 |
| - String currWord = s.substring(start + i * singleWordLength, start + (i + 1) * singleWordLength); |
26 |
| - Integer freq = wordFreqMap.get(currWord); |
27 |
| - // Word not in required words |
28 |
| - if (freq == null) { |
29 |
| - return false; |
30 |
| - } |
31 |
| - currFreqMap.put(currWord, currFreqMap.getOrDefault(currWord, 0) + 1); |
32 |
| - // Word occurs more than the required count |
33 |
| - if (currFreqMap.get(currWord) > freq) { |
34 |
| - return false; |
| 16 | + |
| 17 | + private void slidingWindow(int left, String s, List<Integer> answer, int singleWordLength, |
| 18 | + int totalSubstringLength, Map<String, Integer> wordCount, int numberOfWords) { |
| 19 | + Map<String, Integer> wordsFound = new HashMap<>(); |
| 20 | + int wordsUsed = 0; |
| 21 | + boolean excessWord = false; |
| 22 | + int n = s.length(); |
| 23 | + for (int right = left; right <= n - singleWordLength; right += singleWordLength) { |
| 24 | + String currSubstring = s.substring(right, right + singleWordLength); |
| 25 | + if (!wordCount.containsKey(currSubstring)) { |
| 26 | + wordsFound.clear(); |
| 27 | + wordsUsed = 0; |
| 28 | + excessWord = false; |
| 29 | + left = right + singleWordLength; |
| 30 | + } else { |
| 31 | + while (right - left == totalSubstringLength || excessWord) { |
| 32 | + String leftmostWord = s.substring(left, left + singleWordLength); |
| 33 | + left += singleWordLength; |
| 34 | + wordsFound.put(leftmostWord, wordsFound.get(leftmostWord) - 1); |
| 35 | + if (wordsFound.get(leftmostWord) >= wordCount.get(leftmostWord)) { |
| 36 | + excessWord = false; |
| 37 | + } else { |
| 38 | + wordsUsed--; |
| 39 | + } |
| 40 | + } |
| 41 | + wordsFound.put(currSubstring, wordsFound.getOrDefault(currSubstring, 0) + 1); |
| 42 | + if (wordsFound.get(currSubstring) <= wordCount.get(currSubstring)) { |
| 43 | + wordsUsed++; |
| 44 | + } else { |
| 45 | + excessWord = true; |
| 46 | + } |
| 47 | + if (wordsUsed == numberOfWords && !excessWord) { |
| 48 | + answer.add(left); |
| 49 | + } |
35 | 50 | }
|
36 | 51 | }
|
37 |
| - return true; |
38 | 52 | }
|
39 | 53 | }
|
0 commit comments