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.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
There are some red and blue tiles arranged circularly. You are given an array of integers colors and a 2D integers array queries.
The color of tile i is represented by colors[i]:
colors[i] == 0 means that tile i is red.colors[i] == 1 means that tile i is blue.An alternating group is a contiguous subset of tiles in the circle with alternating colors (each tile in the group except the first and last one has a different color from its adjacent tiles in the group).
You have to process queries of two types:
queries[i] = [1, sizei], determine the count of alternating groups with size sizei.queries[i] = [2, indexi, colori], change colors[indexi] to colori.Return an array answer containing the results of the queries of the first type in order.
Note that since colors represents a circle, the first and the last tiles are considered to be next to each other.
Example 1:
Input: colors = [0,1,1,0,1], queries = [[2,1,0],[1,4]]
Output: [2]
Explanation:
First query:
Change colors[1] to 0.
Second query:
Count of the alternating groups with size 4:
Example 2:
Input: colors = [0,0,1,0,1,1], queries = [[1,3],[2,3,0],[1,5]]
Output: [2,0]
Explanation:
First query:
Count of the alternating groups with size 3:
Second query: colors will not change.
Third query: There is no alternating group with size 5.
Constraints:
4 <= colors.length <= 5 * 1040 <= colors[i] <= 11 <= queries.length <= 5 * 104queries[i][0] == 1 or queries[i][0] == 2i that:
queries[i][0] == 1: queries[i].length == 2, 3 <= queries[i][1] <= colors.length - 1queries[i][0] == 2: queries[i].length == 3, 0 <= queries[i][1] <= colors.length - 1, 0 <= queries[i][2] <= 1Problem summary: There are some red and blue tiles arranged circularly. You are given an array of integers colors and a 2D integers array queries. The color of tile i is represented by colors[i]: colors[i] == 0 means that tile i is red. colors[i] == 1 means that tile i is blue. An alternating group is a contiguous subset of tiles in the circle with alternating colors (each tile in the group except the first and last one has a different color from its adjacent tiles in the group). You have to process queries of two types: queries[i] = [1, sizei], determine the count of alternating groups with size sizei. queries[i] = [2, indexi, colori], change colors[indexi] to colori. Return an array answer containing the results of the queries of the first type in order. Note that since colors represents a circle, the first and the last tiles are considered to be next to each other.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Segment Tree
[0,1,1,0,1] [[2,1,0],[1,4]]
[0,0,1,0,1,1] [[1,3],[2,3,0],[1,5]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3245: Alternating Groups III
// Auto-generated Java example from go.
class Solution {
public void exampleSolution() {
}
}
// Reference (go):
// // Accepted solution for LeetCode #3245: Alternating Groups III
// package main
//
// import "github.com/emirpasic/gods/v2/trees/redblacktree"
//
// // https://space.bilibili.com/206214
// type fenwickTree [][2]int
//
// // op=1,添加一个 size
// // op=-1,移除一个 size
// func (t fenwickTree) update(size, op int) {
// for i := len(t) - size; i < len(t); i += i & -i {
// t[i][0] += op
// t[i][1] += op * size
// }
// }
//
// // 返回 >= size 的元素个数,元素和
// func (t fenwickTree) query(size int) (cnt, sum int) {
// for i := len(t) - size; i > 0; i &= i - 1 {
// cnt += t[i][0]
// sum += t[i][1]
// }
// return
// }
//
// func numberOfAlternatingGroups(a []int, queries [][]int) (ans []int) {
// n := len(a)
// set := redblacktree.New[int, struct{}]()
// t := make(fenwickTree, n+1)
//
// // op=1,添加一个结束位置 i
// // op=-1,移除一个结束位置 i
// update := func(i, op int) {
// prev, ok := set.Floor(i)
// if !ok {
// prev = set.Right()
// }
// pre := prev.Key
//
// next, ok := set.Ceiling(i)
// if !ok {
// next = set.Left()
// }
// nxt := next.Key
//
// t.update((nxt-pre+n-1)%n+1, -op) // 移除/添加旧长度
// t.update((i-pre+n)%n, op)
// t.update((nxt-i+n)%n, op) // 添加/移除新长度
// }
//
// // 添加一个结束位置 i
// add := func(i int) {
// if set.Empty() {
// t.update(n, 1)
// } else {
// update(i, 1)
// }
// set.Put(i, struct{}{})
// }
//
// // 移除一个结束位置 i
// del := func(i int) {
// set.Remove(i)
// if set.Empty() {
// t.update(n, -1)
// } else {
// update(i, -1)
// }
// }
//
// for i, c := range a {
// if c == a[(i+1)%n] {
// add(i) // i 是一个结束位置
// }
// }
// for _, q := range queries {
// if q[0] == 1 {
// if set.Empty() {
// ans = append(ans, n) // 每个长为 size 的子数组都符合要求
// } else {
// cnt, sum := t.query(q[1])
// ans = append(ans, sum-cnt*(q[1]-1))
// }
// } else {
// i := q[1]
// if a[i] == q[2] { // 无影响
// continue
// }
// pre, nxt := (i-1+n)%n, (i+1)%n
// // 修改前,先去掉结束位置
// if a[pre] == a[i] {
// del(pre)
// }
// if a[i] == a[nxt] {
// del(i)
// }
// a[i] ^= 1
// // 修改后,添加新的结束位置
// if a[pre] == a[i] {
// add(pre)
// }
// if a[i] == a[nxt] {
// add(i)
// }
// }
// }
// return
// }
// Accepted solution for LeetCode #3245: Alternating Groups III
package main
import "github.com/emirpasic/gods/v2/trees/redblacktree"
// https://space.bilibili.com/206214
type fenwickTree [][2]int
// op=1,添加一个 size
// op=-1,移除一个 size
func (t fenwickTree) update(size, op int) {
for i := len(t) - size; i < len(t); i += i & -i {
t[i][0] += op
t[i][1] += op * size
}
}
// 返回 >= size 的元素个数,元素和
func (t fenwickTree) query(size int) (cnt, sum int) {
for i := len(t) - size; i > 0; i &= i - 1 {
cnt += t[i][0]
sum += t[i][1]
}
return
}
func numberOfAlternatingGroups(a []int, queries [][]int) (ans []int) {
n := len(a)
set := redblacktree.New[int, struct{}]()
t := make(fenwickTree, n+1)
// op=1,添加一个结束位置 i
// op=-1,移除一个结束位置 i
update := func(i, op int) {
prev, ok := set.Floor(i)
if !ok {
prev = set.Right()
}
pre := prev.Key
next, ok := set.Ceiling(i)
if !ok {
next = set.Left()
}
nxt := next.Key
t.update((nxt-pre+n-1)%n+1, -op) // 移除/添加旧长度
t.update((i-pre+n)%n, op)
t.update((nxt-i+n)%n, op) // 添加/移除新长度
}
// 添加一个结束位置 i
add := func(i int) {
if set.Empty() {
t.update(n, 1)
} else {
update(i, 1)
}
set.Put(i, struct{}{})
}
// 移除一个结束位置 i
del := func(i int) {
set.Remove(i)
if set.Empty() {
t.update(n, -1)
} else {
update(i, -1)
}
}
for i, c := range a {
if c == a[(i+1)%n] {
add(i) // i 是一个结束位置
}
}
for _, q := range queries {
if q[0] == 1 {
if set.Empty() {
ans = append(ans, n) // 每个长为 size 的子数组都符合要求
} else {
cnt, sum := t.query(q[1])
ans = append(ans, sum-cnt*(q[1]-1))
}
} else {
i := q[1]
if a[i] == q[2] { // 无影响
continue
}
pre, nxt := (i-1+n)%n, (i+1)%n
// 修改前,先去掉结束位置
if a[pre] == a[i] {
del(pre)
}
if a[i] == a[nxt] {
del(i)
}
a[i] ^= 1
// 修改后,添加新的结束位置
if a[pre] == a[i] {
add(pre)
}
if a[i] == a[nxt] {
add(i)
}
}
}
return
}
# Accepted solution for LeetCode #3245: Alternating Groups III
# Time: O(nlogn + qlogn)
# Space: O(n)
from sortedcontainers import SortedList
# sorted list, freq table, bit, fenwick tree
class Solution(object):
def numberOfAlternatingGroups(self, colors, queries):
"""
:type colors: List[int]
:type queries: List[List[int]]
:rtype: List[int]
"""
class BIT(object): # 0-indexed.
def __init__(self, n):
self.__bit = [0]*(n+1)
def add(self, i, val):
i += 1
while i < len(self.__bit):
self.__bit[i] += val
i += (i & -i)
def query(self, i):
i += 1
ret = 0
while i > 0:
ret += self.__bit[i]
i -= (i & -i)
return ret
def update(i, d):
if d == +1:
sl.add(i)
if len(sl) == 1:
bit1.add(n, +1)
bit2.add(n, +n)
curr = sl.index(i)
prv, nxt = (curr-1)%len(sl), (curr+1)%len(sl)
if len(sl) != 1:
l = (sl[nxt]-sl[prv]-1)%n+1
bit1.add(l, d*(-1))
bit2.add(l, d*(-l))
l = (sl[curr]-sl[prv])%n
bit1.add(l, d*(+1))
bit2.add(l, d*(+l))
l = (sl[nxt]-sl[curr])%n
bit1.add(l, d*(+1))
bit2.add(l, d*(+l))
if d == -1:
if len(sl) == 1:
bit1.add(n, -1)
bit2.add(n, -n)
sl.pop(curr)
n = len(colors)
sl = SortedList()
bit1, bit2 = BIT(n+1), BIT(n+1)
for i in xrange(n):
if colors[i] == colors[(i+1)%n]:
update(i, +1)
result = []
for q in queries:
if q[0] == 1:
l = q[1]
result.append((bit2.query(n)-bit2.query(l-1))-
(l-1)*(bit1.query(n)-bit1.query(l-1)) if sl else n)
continue
_, i, c = q
if colors[i] == c:
continue
colors[i] = c
update((i-1)%n, +1 if colors[i] == colors[(i-1)%n] else -1)
update(i, +1 if colors[i] == colors[(i+1)%n] else -1)
return result
// Accepted solution for LeetCode #3245: Alternating Groups III
// Rust example auto-generated from go reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (go):
// // Accepted solution for LeetCode #3245: Alternating Groups III
// package main
//
// import "github.com/emirpasic/gods/v2/trees/redblacktree"
//
// // https://space.bilibili.com/206214
// type fenwickTree [][2]int
//
// // op=1,添加一个 size
// // op=-1,移除一个 size
// func (t fenwickTree) update(size, op int) {
// for i := len(t) - size; i < len(t); i += i & -i {
// t[i][0] += op
// t[i][1] += op * size
// }
// }
//
// // 返回 >= size 的元素个数,元素和
// func (t fenwickTree) query(size int) (cnt, sum int) {
// for i := len(t) - size; i > 0; i &= i - 1 {
// cnt += t[i][0]
// sum += t[i][1]
// }
// return
// }
//
// func numberOfAlternatingGroups(a []int, queries [][]int) (ans []int) {
// n := len(a)
// set := redblacktree.New[int, struct{}]()
// t := make(fenwickTree, n+1)
//
// // op=1,添加一个结束位置 i
// // op=-1,移除一个结束位置 i
// update := func(i, op int) {
// prev, ok := set.Floor(i)
// if !ok {
// prev = set.Right()
// }
// pre := prev.Key
//
// next, ok := set.Ceiling(i)
// if !ok {
// next = set.Left()
// }
// nxt := next.Key
//
// t.update((nxt-pre+n-1)%n+1, -op) // 移除/添加旧长度
// t.update((i-pre+n)%n, op)
// t.update((nxt-i+n)%n, op) // 添加/移除新长度
// }
//
// // 添加一个结束位置 i
// add := func(i int) {
// if set.Empty() {
// t.update(n, 1)
// } else {
// update(i, 1)
// }
// set.Put(i, struct{}{})
// }
//
// // 移除一个结束位置 i
// del := func(i int) {
// set.Remove(i)
// if set.Empty() {
// t.update(n, -1)
// } else {
// update(i, -1)
// }
// }
//
// for i, c := range a {
// if c == a[(i+1)%n] {
// add(i) // i 是一个结束位置
// }
// }
// for _, q := range queries {
// if q[0] == 1 {
// if set.Empty() {
// ans = append(ans, n) // 每个长为 size 的子数组都符合要求
// } else {
// cnt, sum := t.query(q[1])
// ans = append(ans, sum-cnt*(q[1]-1))
// }
// } else {
// i := q[1]
// if a[i] == q[2] { // 无影响
// continue
// }
// pre, nxt := (i-1+n)%n, (i+1)%n
// // 修改前,先去掉结束位置
// if a[pre] == a[i] {
// del(pre)
// }
// if a[i] == a[nxt] {
// del(i)
// }
// a[i] ^= 1
// // 修改后,添加新的结束位置
// if a[pre] == a[i] {
// add(pre)
// }
// if a[i] == a[nxt] {
// add(i)
// }
// }
// }
// return
// }
// Accepted solution for LeetCode #3245: Alternating Groups III
// Auto-generated TypeScript example from go.
function exampleSolution(): void {
}
// Reference (go):
// // Accepted solution for LeetCode #3245: Alternating Groups III
// package main
//
// import "github.com/emirpasic/gods/v2/trees/redblacktree"
//
// // https://space.bilibili.com/206214
// type fenwickTree [][2]int
//
// // op=1,添加一个 size
// // op=-1,移除一个 size
// func (t fenwickTree) update(size, op int) {
// for i := len(t) - size; i < len(t); i += i & -i {
// t[i][0] += op
// t[i][1] += op * size
// }
// }
//
// // 返回 >= size 的元素个数,元素和
// func (t fenwickTree) query(size int) (cnt, sum int) {
// for i := len(t) - size; i > 0; i &= i - 1 {
// cnt += t[i][0]
// sum += t[i][1]
// }
// return
// }
//
// func numberOfAlternatingGroups(a []int, queries [][]int) (ans []int) {
// n := len(a)
// set := redblacktree.New[int, struct{}]()
// t := make(fenwickTree, n+1)
//
// // op=1,添加一个结束位置 i
// // op=-1,移除一个结束位置 i
// update := func(i, op int) {
// prev, ok := set.Floor(i)
// if !ok {
// prev = set.Right()
// }
// pre := prev.Key
//
// next, ok := set.Ceiling(i)
// if !ok {
// next = set.Left()
// }
// nxt := next.Key
//
// t.update((nxt-pre+n-1)%n+1, -op) // 移除/添加旧长度
// t.update((i-pre+n)%n, op)
// t.update((nxt-i+n)%n, op) // 添加/移除新长度
// }
//
// // 添加一个结束位置 i
// add := func(i int) {
// if set.Empty() {
// t.update(n, 1)
// } else {
// update(i, 1)
// }
// set.Put(i, struct{}{})
// }
//
// // 移除一个结束位置 i
// del := func(i int) {
// set.Remove(i)
// if set.Empty() {
// t.update(n, -1)
// } else {
// update(i, -1)
// }
// }
//
// for i, c := range a {
// if c == a[(i+1)%n] {
// add(i) // i 是一个结束位置
// }
// }
// for _, q := range queries {
// if q[0] == 1 {
// if set.Empty() {
// ans = append(ans, n) // 每个长为 size 的子数组都符合要求
// } else {
// cnt, sum := t.query(q[1])
// ans = append(ans, sum-cnt*(q[1]-1))
// }
// } else {
// i := q[1]
// if a[i] == q[2] { // 无影响
// continue
// }
// pre, nxt := (i-1+n)%n, (i+1)%n
// // 修改前,先去掉结束位置
// if a[pre] == a[i] {
// del(pre)
// }
// if a[i] == a[nxt] {
// del(i)
// }
// a[i] ^= 1
// // 修改后,添加新的结束位置
// if a[pre] == a[i] {
// add(pre)
// }
// if a[i] == a[nxt] {
// add(i)
// }
// }
// }
// return
// }
Use this to step through a reusable interview workflow for this problem.
For each of q queries, scan the entire range to compute the aggregate (sum, min, max). Each range scan takes up to O(n) for a full-array query. With q queries: O(n × q) total. Point updates are O(1) but queries dominate.
Building the tree is O(n). Each query or update traverses O(log n) nodes (tree height). For q queries: O(n + q log n) total. Space is O(4n) ≈ O(n) for the tree array. Lazy propagation adds O(1) per node for deferred updates.
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.