Find the Longest Semi-Repetitive Substring
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given a digit string s that consists of digits from 0 to 9.
A string is called semi-repetitive if there is at most one adjacent pair of the same digit. For example, "0010", "002020", "0123", "2002", and "54944" are semi-repetitive while the following are not: "00101022"
(adjacent same digit pairs are 00 and 22), and "1101234883" (adjacent same digit pairs are 11 and 88).
Return the length of the longest semi-repetitive substring of s.
Examples
Example 1
Input: s = "52233"
Output: 4
Explanation:
The longest semi-repetitive substring is "5223". Picking the whole string
"52233" has two adjacent same digit pairs 22 and 33, but at most one is
allowed.
Example 2
Input: s = "5494"
Output: 4
Explanation:
`s` is a semi-repetitive string.
Example 3
Input: s = "1111111"
Output: 2
Explanation:
The longest semi-repetitive substring is "11". Picking the substring "111" has
two adjacent same digit pairs, but at most one is allowed.
Constraints
1 <= s.length <= 50'0' <= s[i] <= '9'
Solution
Method 1 – Sliding Window
Intuition
We want the longest substring with at most one pair of adjacent equal digits. We can use a sliding window to keep track of the current substring and count the number of adjacent equal pairs.
Approach
- Initialize two pointers (left and right) for the window and a counter for adjacent equal pairs.
- Move the right pointer through the string:
- If s[right] == s[right-1], increment the counter.
- If the counter exceeds 1, move the left pointer forward and decrement the counter when needed.
- Track the maximum window length where the counter is at most 1.
Code
C++
class Solution {
public:
int longestSemiRepetitiveSubstring(string s) {
int n = s.size(), ans = 1, cnt = 0, l = 0;
for(int r = 1; r < n; ++r) {
if(s[r] == s[r-1]) ++cnt;
while(cnt > 1) {
if(s[l+1] == s[l]) --cnt;
++l;
}
ans = max(ans, r-l+1);
}
return ans;
}
};
Go
func longestSemiRepetitiveSubstring(s string) int {
n, ans, cnt, l := len(s), 1, 0, 0
for r := 1; r < n; r++ {
if s[r] == s[r-1] { cnt++ }
for cnt > 1 {
if s[l+1] == s[l] { cnt-- }
l++
}
if r-l+1 > ans { ans = r-l+1 }
}
return ans
}
Java
class Solution {
public int longestSemiRepetitiveSubstring(String s) {
int n = s.length(), ans = 1, cnt = 0, l = 0;
for(int r = 1; r < n; ++r) {
if(s.charAt(r) == s.charAt(r-1)) ++cnt;
while(cnt > 1) {
if(s.charAt(l+1) == s.charAt(l)) --cnt;
++l;
}
ans = Math.max(ans, r-l+1);
}
return ans;
}
}
Kotlin
class Solution {
fun longestSemiRepetitiveSubstring(s: String): Int {
var ans = 1; var cnt = 0; var l = 0
for (r in 1 until s.length) {
if (s[r] == s[r-1]) cnt++
while (cnt > 1) {
if (s[l+1] == s[l]) cnt--
l++
}
ans = maxOf(ans, r-l+1)
}
return ans
}
}
Python
class Solution:
def longestSemiRepetitiveSubstring(self, s: str) -> int:
n = len(s)
ans = 1
cnt = 0
l = 0
for r in range(1, n):
if s[r] == s[r-1]:
cnt += 1
while cnt > 1:
if s[l+1] == s[l]:
cnt -= 1
l += 1
ans = max(ans, r-l+1)
return ans
Rust
impl Solution {
pub fn longest_semi_repetitive_substring(s: String) -> i32 {
let s = s.as_bytes();
let n = s.len();
let (mut ans, mut cnt, mut l) = (1, 0, 0);
for r in 1..n {
if s[r] == s[r-1] { cnt += 1; }
while cnt > 1 {
if s[l+1] == s[l] { cnt -= 1; }
l += 1;
}
ans = ans.max(r-l+1);
}
ans as i32
}
}
TypeScript
class Solution {
longestSemiRepetitiveSubstring(s: string): number {
let n = s.length, ans = 1, cnt = 0, l = 0;
for(let r=1;r<n;++r) {
if(s[r]===s[r-1]) ++cnt;
while(cnt>1) {
if(s[l+1]===s[l]) --cnt;
++l;
}
ans = Math.max(ans, r-l+1);
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n), since each character is visited at most twice. - 🧺 Space complexity:
O(1), only a few variables are used.