Find K-Length Substrings With No Repeated Characters
Medium · Sliding Window · Explanation and code example
Sliding Window
How it works
Instead of recomputing character frequencies for each substring from scratch, we can maintain a sliding window. As we move the window, we add the new character on the right and remove the character that falls off on the left. When a duplicate is detected, we shrink the window from the left until all characters are unique again.
Steps
- If
k > 26, return0(impossible to havekunique characters). - Initialize two pointers
left = 0andright = 0, and a frequency array. - While
right < n:- Add
s[right]to the frequency array. - While the frequency of
s[right]exceeds1, removes[left]from the window and incrementleft. - If the window size equals
k, increment the answer, then shrink the window from the left by one to prepare for the next position. - Move
rightforward.
- Add
- Return the answer.
Complexity
- Time complexity:
O(n) - Space complexity:
O(m)
Where
nis the length ofsandmis the number of unique characters allowed in the string. In this case,m=26.
Things to watch for
Not Handling k Greater Than 26
Since the string contains only lowercase English letters, it's impossible to have a substring of length greater than 26 with all unique characters. Forgetting to add an early return for k > 26 leads to unnecessary computation or incorrect results when the problem guarantees such substrings cannot exist.
Incorrect Window Shrinking Logic
In the sliding window approach, when a duplicate character is found, you must shrink the window from the left until the duplicate is removed. A common mistake is shrinking by exactly one position or shrinking until the window size is less than k. The correct approach is to shrink until the frequency of the newly added character becomes 1.
Off-by-One Errors in Loop Bounds
When iterating through possible starting positions for substrings of length k, the loop should run from 0 to n - k (inclusive). Using n - k + 1 as the upper bound or forgetting the inclusive boundary leads to either missing valid substrings or accessing indices out of bounds.
Python code example
class Solution:
def numKLenSubstrNoRepeats(self, s: str, k: int) -> int:
# We can reuse the condition from the first approach
# as for k > 26, there can be no substrings with only unique characters
if k > 26:
return 0
answer = 0
n = len(s)
# Initializing the left and right pointers
left = right = 0
# Initializing an empty frequency array
freq = [0] * 26
# Function to obtain the index of a character according to the alphabet
def get_val(ch: str) -> int:
return ord(ch) - ord("a")
while right < n:
# Add the current character in the frequency array
freq[get_val(s[right])] += 1
# If the current character appears more than once in the frequency array
# keep contracting the window and removing characters from the
# frequency array till the frequency of the current character becomes 1.
while freq[get_val(s[right])] > 1:
freq[get_val(s[left])] -= 1
left += 1
# Check if the length of the current unique substring is equal to k
if right - left + 1 == k:
answer += 1
# Contract the window and remove the leftmost character from the
# frequency array
freq[get_val(s[left])] -= 1
left += 1
# Expand the window
right += 1
return answer
C++ code example
class Solution {
public:
int numKLenSubstrNoRepeats(string s, int k) {
// We can reuse the condition from the first approach
// as for k > 26, there can be no substrings with only unique characters
if (k > 26) return 0;
int answer = 0;
int n = s.size();
// Initializing the left and right pointers
int left = 0, right = 0;
// Initializing an empty frequency array
int freq[26] = {0};
while (right < n) {
// Add the current character in the frequency array
freq[s[right] - 'a']++;
// If the current character appears more than once in the frequency
// array keep contracting the window and removing characters from
// the frequency array till the frequency of the current character
// becomes 1.
while (freq[s[right] - 'a'] > 1) {
freq[s[left] - 'a']--;
left++;
}
// Check if the length of the current unique substring is equal to k
if (right - left + 1 == k) {
answer++;
// Contract the window and remove the leftmost character from
// the frequency array
freq[s[left] - 'a']--;
left++;
}
// Expand the window
right++;
}
return answer;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.