Prerequisites
Before attempting this problem, you should be comfortable with:
- Sliding Window - Used to efficiently maintain a window of k characters while tracking character uniqueness
- Hash Map / Frequency Array - Used to track character counts within the current window
- String Manipulation - Understanding how to iterate through substrings and track character frequencies
1. Brute Force
Intuition
The most direct approach is to examine every substring of length k and check if it contains all unique characters. For each starting position, we scan k characters and track their frequencies. If any character appears more than once, we stop early and move to the next substring.
Algorithm
- If
k > 26, return0immediately since there are only 26 lowercase letters. - For each starting index
ifrom0ton - k:- Initialize a frequency array of size 26.
- Iterate through the next
kcharacters. - Increment the frequency of each character.
- If any frequency exceeds
1, break out of the inner loop (duplicate found). - If we complete the inner loop without duplicates, increment the answer.
- Return the count of valid substrings.
class Solution:
def numKLenSubstrNoRepeats(self, s: str, k: int) -> int:
if k > 26:
return 0
answer = 0
n = len(s)
for i in range(n - k + 1):
# Initializing an empty frequency array
freq = [0] * 26
for j in range(i, i + k):
curr_char = ord(s[j]) - ord("a")
# Incrementing the frequency of current character
freq[curr_char] += 1
# If a repeated character is found, we stop the loop
if freq[curr_char] > 1:
break
else:
# If the substring does not have any repeated characters,
# we increment the answer
answer += 1
return answerTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of
s, is the given substring length, and is the number of unique characters allowed in the string. In this case, .
2. Sliding Window
Intuition
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.
Algorithm
- 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.
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 answerTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of
sand is the number of unique characters allowed in the string. In this case, .
Common Pitfalls
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.