Skip to content

Commit 8ed59b7

Browse files
solves #30: Substring with Concatenation of All Words in java
1 parent 042029d commit 8ed59b7

File tree

3 files changed

+115
-18
lines changed

3 files changed

+115
-18
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
| 27 | [Remove Element](https://leetcode.com/problems/remove-element/) | [![Java](assets/java.png)](src/RemoveElement.java) [![Python](assets/python.png)](python/remove_element.py) | |
3838
| 28 | [Needle in Haystack](https://leetcode.com/problems/implement-strstr) | [![Java](assets/java.png)](src/NeedleInHaystack.java) [![Python](assets/python.png)](python/needle_in_haystack.py) | |
3939
| 29 | [Divide Two Integers](https://leetcode.com/problems/divide-two-integers) | [![Java](assets/java.png)](src/DivideTwoIntegers.java) | |
40+
| 30 | [Substring with Concatenation of All Words](https://leetcode.com/problems/substring-with-concatenation-of-all-words) | [![Java](assets/java.png)](src/SubstringWithConcatenationOfAllWords.java) | |
4041
| 31 | [Next Permutation](https://leetcode.com/problems/next-permutation) | [![Java](assets/java.png)](src/NextPermutation.java) | |
4142
| 33 | [Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array) | [![Java](assets/java.png)](src/SearchInRotatedSortedArray.java) | |
4243
| 34 | [Find First and Last Position of Element in Sorted Array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array) | [![Java](assets/java.png)](src/FindFirstAndLastPositionOfElementInSortedArray.java) | |

src/HelloWorld.java

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.Collections;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Set;
7+
18
public class HelloWorld {
2-
public int strStr(String haystack, String needle) {
3-
if (needle.length() > haystack.length()) {
4-
return -1;
9+
public int lengthOfLongestSubstring(String s) {
10+
if (s.isEmpty()) {
11+
return 0;
512
}
613

7-
for (int i = 0 ; i < haystack.length() ; i++) {
8-
if (needle.charAt(0) == haystack.charAt(i) && containsAt(haystack, needle, i)) {
9-
return i;
14+
int maxLength = 1;
15+
final Set<Character> slidingWindow = new HashSet<>() {{
16+
add(s.charAt(0));
17+
}};
18+
19+
for (int left = 0, right = 1, currentLength = 1 ; right < s.length() ; ) {
20+
if (slidingWindow.contains(s.charAt(right))) {
21+
slidingWindow.remove(s.charAt(left));
22+
left++;
23+
currentLength--;
24+
} else {
25+
slidingWindow.add(s.charAt(right));
26+
currentLength++;
27+
maxLength = Math.max(maxLength, currentLength);
28+
right++;
1029
}
1130
}
1231

13-
return -1;
14-
}
1532

16-
private static boolean containsAt(String haystack, String needle, int i) {
17-
if (needle.length() > haystack.length() - i) {
18-
return false;
19-
}
20-
for (int index = i + 1 ; index < haystack.length() && index - i < needle.length() ; index++) {
21-
if (needle.charAt(index - i) != haystack.charAt(index)) {
22-
return false;
23-
}
24-
}
25-
return true;
33+
return maxLength;
2634
}
2735
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// https://leetcode.com/problems/substring-with-concatenation-of-all-words
2+
// T: O(|words| + |s| * |words[i]|)
3+
// S: O(|words| + |words[i]|)
4+
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
class SubstringWithConcatenationOfAllWords {
11+
private final Map<String, Integer> wordCount = new HashMap<>();
12+
private int n;
13+
private int wordLength;
14+
private int substringSize;
15+
private int k;
16+
17+
private void slidingWindow(int left, String s, List<Integer> answer) {
18+
HashMap<String, Integer> wordsFound = new HashMap<>();
19+
int wordsUsed = 0;
20+
boolean excessWord = false;
21+
22+
// Do the same iteration pattern as the previous approach - iterate
23+
// word_length at a time, and at each iteration we focus on one word
24+
for (int right = left; right <= n - wordLength; right += wordLength) {
25+
String sub = s.substring(right, right + wordLength);
26+
if (!wordCount.containsKey(sub)) {
27+
// Mismatched word - reset the window
28+
wordsFound.clear();
29+
wordsUsed = 0;
30+
excessWord = false;
31+
left = right + wordLength;
32+
} else {
33+
// If we reached max window size or have an excess word
34+
while (right - left == substringSize || excessWord) {
35+
String leftmostWord = s.substring(left, left + wordLength);
36+
left += wordLength;
37+
wordsFound.put(
38+
leftmostWord,
39+
wordsFound.get(leftmostWord) - 1
40+
);
41+
42+
if (
43+
wordsFound.get(leftmostWord) >=
44+
wordCount.get(leftmostWord)
45+
) {
46+
// This word was an excess word
47+
excessWord = false;
48+
} else {
49+
// Otherwise we actually needed it
50+
wordsUsed--;
51+
}
52+
}
53+
54+
// Keep track of how many times this word occurs in the window
55+
wordsFound.put(sub, wordsFound.getOrDefault(sub, 0) + 1);
56+
if (wordsFound.get(sub) <= wordCount.get(sub)) {
57+
wordsUsed++;
58+
} else {
59+
// Found too many instances already
60+
excessWord = true;
61+
}
62+
63+
if (wordsUsed == k && !excessWord) {
64+
// Found a valid substring
65+
answer.add(left);
66+
}
67+
}
68+
}
69+
}
70+
71+
public List<Integer> findSubstring(String s, String[] words) {
72+
n = s.length();
73+
k = words.length;
74+
wordLength = words[0].length();
75+
substringSize = wordLength * k;
76+
77+
for (String word : words) {
78+
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
79+
}
80+
81+
List<Integer> answer = new ArrayList<>();
82+
for (int i = 0; i < wordLength; i++) {
83+
slidingWindow(i, s, answer);
84+
}
85+
86+
return answer;
87+
}
88+
}

0 commit comments

Comments
 (0)