Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Build confidence with an intuition-first walkthrough focused on core interview patterns fundamentals.
In a string s of lowercase letters, these letters form consecutive groups of the same character.
For example, a string like s = "abbxxxxzyy" has the groups "a", "bb", "xxxx", "z", and "yy".
A group is identified by an interval [start, end], where start and end denote the start and end indices (inclusive) of the group. In the above example, "xxxx" has the interval [3,6].
A group is considered large if it has 3 or more characters.
Return the intervals of every large group sorted in increasing order by start index.
Example 1:
Input: s = "abbxxxxzzy"
Output: [[3,6]]
Explanation: "xxxx" is the only large group with start index 3 and end index 6.
Example 2:
Input: s = "abc" Output: [] Explanation: We have groups "a", "b", and "c", none of which are large groups.
Example 3:
Input: s = "abcdddeeeeaabbbcd" Output: [[3,5],[6,9],[12,14]] Explanation: The large groups are "ddd", "eeee", and "bbb".
Constraints:
1 <= s.length <= 1000s contains lowercase English letters only.Problem summary: In a string s of lowercase letters, these letters form consecutive groups of the same character. For example, a string like s = "abbxxxxzyy" has the groups "a", "bb", "xxxx", "z", and "yy". A group is identified by an interval [start, end], where start and end denote the start and end indices (inclusive) of the group. In the above example, "xxxx" has the interval [3,6]. A group is considered large if it has 3 or more characters. Return the intervals of every large group sorted in increasing order by start index.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
"abbxxxxzzy"
"abc"
"abcdddeeeeaabbbcd"
divide-a-string-into-groups-of-size-k)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #830: Positions of Large Groups
class Solution {
public List<List<Integer>> largeGroupPositions(String s) {
int n = s.length();
int i = 0;
List<List<Integer>> ans = new ArrayList<>();
while (i < n) {
int j = i;
while (j < n && s.charAt(j) == s.charAt(i)) {
++j;
}
if (j - i >= 3) {
ans.add(List.of(i, j - 1));
}
i = j;
}
return ans;
}
}
// Accepted solution for LeetCode #830: Positions of Large Groups
func largeGroupPositions(s string) [][]int {
i, n := 0, len(s)
ans := [][]int{}
for i < n {
j := i
for j < n && s[j] == s[i] {
j++
}
if j-i >= 3 {
ans = append(ans, []int{i, j - 1})
}
i = j
}
return ans
}
# Accepted solution for LeetCode #830: Positions of Large Groups
class Solution:
def largeGroupPositions(self, s: str) -> List[List[int]]:
i, n = 0, len(s)
ans = []
while i < n:
j = i
while j < n and s[j] == s[i]:
j += 1
if j - i >= 3:
ans.append([i, j - 1])
i = j
return ans
// Accepted solution for LeetCode #830: Positions of Large Groups
struct Solution;
struct Group {
c: char,
start: usize,
end: usize,
}
impl Solution {
fn large_group_positions(s: String) -> Vec<Vec<i32>> {
let mut prev: Option<Group> = None;
let mut groups: Vec<Group> = vec![];
for (i, c) in s.chars().enumerate() {
if let Some(prev_group) = prev {
if prev_group.c == c {
prev = Some(Group {
c,
start: prev_group.start,
end: i,
});
} else {
groups.push(prev_group);
prev = Some(Group {
c,
start: i,
end: i,
});
}
} else {
prev = Some(Group {
c,
start: i,
end: i,
});
}
}
if let Some(prev_group) = prev {
groups.push(prev_group);
}
groups
.iter()
.filter_map(|g| {
let start = g.start;
let end = g.end;
if end - start > 1 {
Some(vec![start as i32, end as i32])
} else {
None
}
})
.collect()
}
}
#[test]
fn test() {
let s = "abbxxxxzzy".to_string();
let res: Vec<Vec<i32>> = vec_vec_i32![[3, 6]];
assert_eq!(Solution::large_group_positions(s), res);
let s = "abc".to_string();
let res: Vec<Vec<i32>> = vec![];
assert_eq!(Solution::large_group_positions(s), res);
let s = "abcdddeeeeaabbbcd".to_string();
let res: Vec<Vec<i32>> = vec_vec_i32![[3, 5], [6, 9], [12, 14]];
assert_eq!(Solution::large_group_positions(s), res);
}
// Accepted solution for LeetCode #830: Positions of Large Groups
function largeGroupPositions(s: string): number[][] {
const n = s.length;
const ans: number[][] = [];
for (let i = 0; i < n; ) {
let j = i;
while (j < n && s[j] === s[i]) {
++j;
}
if (j - i >= 3) {
ans.push([i, j - 1]);
}
i = j;
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.