publicstatic List<String> kSubstring1(String s, int k) { intn= s.length(); Set<String> result = newHashSet<>(); for (inti=0; i + k <= n; ++i) { Stringsub= s.substring(i, i + k); if (isDistinct(sub)) { result.add(sub); } } returnnewArrayList<>(result); }
privatestaticbooleanisDistinct(String s) { // Use hash set Set<Character> set = newHashSet<>(); for (char ch : s.toCharArray()) { set.add(ch); } return set.size() == s.length(); }
Time: $O(kN)$ where $N$ is the length of the string. Space: $O(kN)$ since we need to store the result.
Sliding Window
Consider the follow examples for the sliding window to see why it works.
1 2 3
"abc" "aba" "abb"
start and end denote the range of the window. Particularly, end is the cursor that from 0 to n - 1.
publicstatic List<String> kSubstring2(String s, int k) { intn= s.length(); Set<Character> window = newHashSet<>(); Set<String> result = newHashSet<>(); for (intstart=0, end = 0; end < n; ++end) { charch= s.charAt(end); // duplicate: remove all elements that is before the existing element (inclusive) while (window.contains(ch)) { window.remove(s.charAt(start)); ++start; // update the lower bound of the sliding window } window.add(ch); // when size == k if (window.size() == k) { // guarantee no duplicates result.add(s.substring(start, end + 1)); // added window.remove(s.charAt(start)); ++start; // guarantee the size is not larger than k } } returnnewArrayList<>(result); }