Find Special Substring of Length K
EasyPrompt
You are given a string s and an integer k.
Determine if there exists a substring of length exactly k in s that satisfies the following conditions:
- The substring consists of only one distinct character (e.g.,
"aaa"or"bbb"). - If there is a character immediately before the substring, it must be different from the character in the substring.
- If there is a character immediately after the substring, it must also be different from the character in the substring.
Return true if such a substring exists. Otherwise, return false.
Example 1:
Input: s = "aaabaaa", k = 3
Output: true
Explanation:
The substring s[4..6] == "aaa" satisfies the conditions.
- It has a length of 3.
- All characters are the same.
- The character before
"aaa"is'b', which is different from'a'. - There is no character after
"aaa".
Example 2:
Input: s = "abc", k = 2
Output: false
Explanation:
There is no substring of length 2 that consists of one distinct character and satisfies the conditions.
Constraints:
1 <= k <= s.length <= 100sconsists of lowercase English letters only.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the problem statement into code. It iterates through every possible substring of length k and, for each one, verifies if it meets all three specified conditions.
Algorithm
- Iterate with an index
ifrom0tos.length() - k. - Inside the loop, consider the substring
s[i...i+k-1]as a candidate. - Check Condition 1: Verify that all characters in
s[i...i+k-1]are the same. If not,continueto the nexti. - Check Condition 2: Check if the character before the substring (if it exists, i.e.,
i > 0) is different from the substring's character. - Check Condition 3: Check if the character after the substring (if it exists, i.e.,
i + k < s.length()) is different from the substring's character. - If all three conditions are met, return
true. - If the loop finishes without finding a valid substring, return
false.
Walkthrough
The algorithm iterates from the first possible starting position of a substring of length k (index 0) up to the last possible one (index n-k, where n is the string length).
For each starting index i, we consider the substring s[i...i+k-1].
We then perform three checks:
- Homogeneous Characters: A nested loop checks if all characters from
s[i+1]tos[i+k-1]are identical tos[i]. If not, we move to the next starting indexi+1. - Preceding Character: If the substring doesn't start at the beginning of the string (
i > 0), we check if the characters[i-1]is different from the substring's characters[i]. - Succeeding Character: If the substring doesn't end at the very end of the string (
i+k < n), we check if the characters[i+k]is different from the substring's characters[i].
If a substring passes all three checks, we have found a special substring, and the function immediately returns true.
If the outer loop completes without finding any such substring, it means none exist, and the function returns false.
class Solution { public boolean findSpecialSubstring(String s, int k) { int n = s.length(); if (k > n) { return false; } // Iterate through all possible start indices of a substring of length k for (int i = 0; i <= n - k; i++) { char firstChar = s.charAt(i); // Condition 1: All characters in the substring are the same boolean allSame = true; for (int j = 1; j < k; j++) { if (s.charAt(i + j) != firstChar) { allSame = false; break; } } if (!allSame) { continue; } // Condition 2: Character before is different boolean beforeIsDifferent = (i == 0) || (s.charAt(i - 1) != firstChar); // Condition 3: Character after is different boolean afterIsDifferent = (i + k == n) || (s.charAt(i + k) != firstChar); if (beforeIsDifferent && afterIsDifferent) { return true; // Found a special substring } } return false; // No special substring found }}Complexity
Time
O(n * k), where `n` is the length of `s`. The outer loop runs `n-k+1` times (which is O(n)), and the inner check for character homogeneity takes `O(k)` time in the worst case.
Space
O(1), as we only use a few variables to store indices and characters, requiring constant extra space.
Trade-offs
Pros
Simple to understand and implement directly from the problem description.
Correctly solves the problem for all valid inputs.
Cons
Inefficient due to the nested loop structure, with a time complexity of O(n*k).
Performs redundant checks, as overlapping substrings are re-evaluated from scratch.
A more efficient approach is to reframe the problem. A "special substring" of length k is essentially a maximal block of identical characters whose length is exactly k. A maximal block is one that is bordered by different characters or the ends of the string. This approach iterates through the string once to find the lengths of these consecutive character groups.
Algorithm
- If
s.length() < k, returnfalseimmediately. - Initialize
consecutiveCount = 1(for the first character's group). - Iterate with an index
ifrom1tos.length() - 1. - If
s.charAt(i) == s.charAt(i - 1), incrementconsecutiveCount. - Else (if
s.charAt(i) != s.charAt(i - 1)), a group has ended:- Check if
consecutiveCount == k. If true, returntrue. - Reset
consecutiveCount = 1for the new group.
- Check if
- After the loop, the last group hasn't been checked. Perform a final check: if
consecutiveCount == k, returntrue. - If no such group was found, return
false.
Walkthrough
The algorithm scans the string from left to right, keeping a count of the current number of consecutive identical characters.
We initialize a count to 1 and start iterating from the second character of the string (i=1).
In each step, we compare the current character s[i] with the previous one s[i-1].
- If they are the same, we increment our
count. - If they are different, it signifies the end of a consecutive block. We then check if the
countof the block that just ended is equal tok. If it is, we've found our special substring and can returntrue. After the check, we reset thecountto 1 for the new block starting withs[i].
A special case is the very last block of characters in the string. Its end is not marked by a different character but by the end of the string itself. Therefore, after the loop finishes, we must perform one final check on the current count to see if the last block has a length of k.
If the loop completes and the final check fails, no special substring was found, and we return false.
class Solution { public boolean findSpecialSubstring(String s, int k) { int n = s.length(); if (n < k) { return false; } int consecutiveCount = 1; for (int i = 1; i < n; i++) { if (s.charAt(i) == s.charAt(i - 1)) { consecutiveCount++; } else { // A new character group starts, check the length of the previous one. if (consecutiveCount == k) { return true; } // Reset count for the new group. consecutiveCount = 1; } } // After the loop, check the length of the last group of characters. return consecutiveCount == k; }}Complexity
Time
O(n), where `n` is the length of `s`. We iterate through the string only once, making it a linear time solution.
Space
O(1), as we only use a constant amount of extra space for the counter and loop index.
Trade-offs
Pros
Highly efficient with optimal linear time complexity.
Avoids redundant checks by processing each character only once.
Cons
The logic is slightly less direct than the brute-force approach.
Requires careful handling of the edge case for the last group of characters after the loop finishes.
Solutions
Solution
class Solution {public boolean hasSpecialSubstring(String s, int k) { int n = s.length(); for (int l = 0, cnt = 0; l < n;) { int r = l + 1; while (r < n && s.charAt(r) == s.charAt(l)) { ++r; } if (r - l == k) { return true; } l = r; } return false; }}class Solution {public: bool hasSpecialSubstring(string s, int k) { int n = s.length(); for (int l = 0, cnt = 0; l < n;) { int r = l + 1; while (r < n && s[r] == s[l]) { ++r; } if (r - l == k) { return true; } l = r; } return false; }};class Solution: def hasSpecialSubstring(self, s: str, k: int) -> bool: l, n = 0, len(s) while l < n: r = l while r < n and s[r] == s[l]: r += 1 if r - l == k: return True l = r return FalseVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.