LeetCode 1446 - Consecutive Characters
The problem asks us to compute the power of a string. The power is defined as the length of the longest contiguous subst
Difficulty: 🟢 Easy
Topics: String
Solution
Problem Understanding
The problem asks us to compute the power of a string. The power is defined as the length of the longest contiguous substring that contains only one distinct character.
In simpler terms, we need to find the longest streak of the same character appearing consecutively in the string. We are not looking for the most frequent character overall, only the longest uninterrupted sequence.
For example, in "leetcode", the character 'e' appears consecutively as "ee", which has length 2. No other character forms a longer consecutive sequence, so the answer is 2.
In "abbcccddddeeeeedcba", the substring "eeeee" contains five consecutive 'e' characters. Even though there are also repeated 'd' characters ("dddd"), the sequence of 'e' is longer, so the result is 5.
The input is a single string s consisting only of lowercase English letters. The output is a single integer representing the maximum length of any consecutive block of identical characters.
The constraints are relatively small:
1 <= s.length <= 500scontains only lowercase English letters
These constraints tell us that performance is not a major concern because the string is short. Even a quadratic solution would pass comfortably. However, the problem has a very natural linear-time solution that scans the string once.
There are several important edge cases to consider. A string of length 1 should return 1, since a single character itself forms a valid substring. A string where every character is the same, such as "aaaaaa", should return the full length of the string. A string with no consecutive repetitions, such as "abcdef", should return 1. The problem guarantees that the string is never empty, so we never need to handle an invalid or empty input.
Approaches
Brute Force Approach
A straightforward way to solve this problem is to examine every possible substring and check whether it contains only one unique character.
For each starting position, we could extend the substring one character at a time and verify whether all characters remain identical. If the substring consists of a single repeated character, we update the maximum length.
This method is correct because it exhaustively considers every candidate substring. Eventually, it will encounter the longest valid substring and record its length.
However, this approach is inefficient. There are O(n²) substrings in total, and validating each substring may take additional work. Even with optimizations, the time complexity becomes unnecessarily large for a problem that only requires tracking consecutive identical characters.
Optimal Approach, Single Pass Tracking
The key observation is that we only care about consecutive runs of characters.
Instead of checking every substring, we can scan the string from left to right and count the length of the current streak of identical characters.
Whenever the current character matches the previous one, we extend the streak. Otherwise, we start a new streak of length 1. While doing this, we continuously track the maximum streak length encountered so far.
This works because every valid substring made of one repeated character belongs to exactly one consecutive run. By measuring each run once, we naturally find the longest one.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Checks all possible substrings and validates repeated characters |
| Optimal | O(n) | O(1) | Single scan while counting consecutive identical characters |
Algorithm Walkthrough
- Initialize two variables:
current_lengthandmax_length, both starting at1. Since the string is guaranteed to be non-empty, the smallest valid power is always1. - Iterate through the string starting from index
1, comparing each character with the previous character. - If the current character is the same as the previous character, increment
current_lengthbecause the consecutive streak continues. - If the current character differs, reset
current_lengthto1because a new streak begins with the current character. - After each update, compare
current_lengthwithmax_length. If the current streak is larger, updatemax_length. - After processing the entire string, return
max_length.
Why it works
The algorithm maintains an important invariant: at every position in the string, current_length represents the length of the consecutive sequence ending at the current character, while max_length stores the largest sequence seen so far. Since every consecutive block is processed exactly once, and we update the maximum whenever we find a longer streak, the final value of max_length must be the power of the string.
Python Solution
class Solution:
def maxPower(self, s: str) -> int:
current_length = 1
max_length = 1
for index in range(1, len(s)):
if s[index] == s[index - 1]:
current_length += 1
else:
current_length = 1
max_length = max(max_length, current_length)
return max_length
The implementation starts by initializing both current_length and max_length to 1, because the string always contains at least one character.
The loop begins from index 1 since each character must be compared with its predecessor. If the current character matches the previous one, the streak continues and current_length increases by one.
When the characters differ, the current streak ends, so we reset current_length to 1, representing the new character starting its own sequence.
After each iteration, we update max_length using max() to ensure we always retain the longest streak encountered during traversal.
Finally, once the scan is complete, we return max_length.
Go Solution
func maxPower(s string) int {
currentLength := 1
maxLength := 1
for i := 1; i < len(s); i++ {
if s[i] == s[i-1] {
currentLength++
} else {
currentLength = 1
}
if currentLength > maxLength {
maxLength = currentLength
}
}
return maxLength
}
The Go implementation follows the exact same logic as the Python solution. Since strings in Go can be indexed directly by byte and the problem guarantees lowercase English letters, character comparison is straightforward.
There are no concerns about integer overflow because the maximum string length is only 500. Since the input is guaranteed to be non-empty, we safely initialize both counters to 1 without special handling for empty strings.
Worked Examples
Example 1
Input: s = "leetcode"
We track the current streak length and the maximum streak found so far.
| Index | Character | Previous Character | Current Length | Max Length |
|---|---|---|---|---|
| 0 | l | N/A | 1 | 1 |
| 1 | e | l | 1 | 1 |
| 2 | e | e | 2 | 2 |
| 3 | t | e | 1 | 2 |
| 4 | c | t | 1 | 2 |
| 5 | o | c | 1 | 2 |
| 6 | d | o | 1 | 2 |
| 7 | e | d | 1 | 2 |
The longest consecutive sequence is "ee", so the answer is 2.
Example 2
Input: s = "abbcccddddeeeeedcba"
| Index | Character | Previous Character | Current Length | Max Length |
|---|---|---|---|---|
| 0 | a | N/A | 1 | 1 |
| 1 | b | a | 1 | 1 |
| 2 | b | b | 2 | 2 |
| 3 | c | b | 1 | 2 |
| 4 | c | c | 2 | 2 |
| 5 | c | c | 3 | 3 |
| 6 | d | c | 1 | 3 |
| 7 | d | d | 2 | 3 |
| 8 | d | d | 3 | 3 |
| 9 | d | d | 4 | 4 |
| 10 | e | d | 1 | 4 |
| 11 | e | e | 2 | 4 |
| 12 | e | e | 3 | 4 |
| 13 | e | e | 4 | 4 |
| 14 | e | e | 5 | 5 |
| 15 | d | e | 1 | 5 |
| 16 | c | d | 1 | 5 |
| 17 | b | c | 1 | 5 |
| 18 | a | b | 1 | 5 |
The longest streak is "eeeee" with length 5, so the answer is 5.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | We scan the string once, visiting each character exactly one time |
| Space | O(1) | Only a few integer variables are used |
The algorithm is linear because every character is processed exactly once during the traversal. No nested loops or repeated work are involved. Space complexity remains constant because we only maintain counters regardless of input size.
Test Cases
solution = Solution()
assert solution.maxPower("leetcode") == 2 # Example case with repeated 'e'
assert solution.maxPower("abbcccddddeeeeedcba") == 5 # Example case with longest 'eeeee'
assert solution.maxPower("a") == 1 # Minimum input size
assert solution.maxPower("aaaaa") == 5 # Entire string is one repeated character
assert solution.maxPower("abcde") == 1 # No consecutive repetition
assert solution.maxPower("aaabbb") == 3 # Multiple equal maximum streaks
assert solution.maxPower("aabbbbbcc") == 5 # Longest streak in middle
assert solution.maxPower("abcccc") == 4 # Longest streak at end
assert solution.maxPower("zzzza") == 4 # Longest streak at beginning
assert solution.maxPower("abababab") == 1 # Alternating characters
assert solution.maxPower("bbbaaacccddd") == 3 # Several identical maximum streaks
| Test | Why |
|---|---|
"leetcode" |
Verifies the first provided example |
"abbcccddddeeeeedcba" |
Verifies the second provided example |
"a" |
Tests minimum valid input |
"aaaaa" |
Tests when entire string is one sequence |
"abcde" |
Tests no consecutive duplicates |
"aaabbb" |
Tests tied maximum streaks |
"aabbbbbcc" |
Tests longest streak in middle |
"abcccc" |
Tests longest streak at end |
"zzzza" |
Tests longest streak at beginning |
"abababab" |
Tests alternating characters |
"bbbaaacccddd" |
Tests repeated equal-length streaks |
Edge Cases
One important edge case is a string containing only a single character, such as "a". A careless implementation might initialize counters incorrectly or assume there are at least two characters to compare. This implementation handles the case naturally by initializing both counters to 1 and skipping the loop entirely, returning the correct answer.
Another important case is when the entire string consists of one repeated character, such as "aaaaaa". A buggy implementation might forget to update the maximum after extending the streak, especially at the end of the string. Since this solution updates max_length during every iteration, the final longest streak is recorded correctly.
A third edge case occurs when there are no repeated adjacent characters, such as "abcdef". In this situation, every streak has length 1. The implementation correctly resets current_length to 1 at every character transition, and max_length never exceeds 1.
A final tricky case is when multiple streaks have the same maximum length, such as "aaabbbccc". The algorithm does not need to track which character created the streak, only the maximum length. Because max_length stores the best result seen so far, ties are handled automatically and the correct value is returned.