3245. Alternating Groups III LeetCode Solution
In this guide, you will get 3245. Alternating Groups III LeetCode Solution with the best time and space complexity. The solution to Alternating Groups III problem is provided in various programming languages like C++, Java, and Python. This will be helpful for you if you are preparing for placements, hackathons, interviews, or practice purposes. The solutions provided here are very easy to follow and include detailed explanations.
Table of Contents
- Problem Statement
- Complexity Analysis
- Alternating Groups III solution in C++
- Alternating Groups III solution in Java
- Alternating Groups III solution in Python
- Additional Resources
Problem Statement of Alternating Groups III
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 * 104
0 <= colors[i] <= 1
1 <= queries.length <= 5 * 104
queries[i][0] == 1 or queries[i][0] == 2
For all i that:
queries[i][0] == 1: queries[i].length == 2, 3 <= queries[i][1] <= colors.length – 1
queries[i][0] == 2: queries[i].length == 3, 0 <= queries[i][1] <= colors.length – 1, 0 <= queries[i][2] <= 1
Complexity Analysis
- Time Complexity: O(n + q\log n)
- Space Complexity: O(n + q)
3245. Alternating Groups III LeetCode Solution in C++
struct SegmentTree {
public:
explicit SegmentTree(int n)
: n(n), treeIntervalCounts(4 * n), treeIntervalLengths(4 * n) {}
// Adds val to intervalCounts[i] and updates intervalLengths[i] accordingly.
void add(int i, int val) {
add(0, 0, n - 1, i, val);
}
// Returns sum(intervalCounts[i..n - 1]).
int queryIntervalCounts(int i) const {
return query(treeIntervalCounts, 0, 0, n - 1, i, n - 1);
}
// Returns sum(intervalLengths[i..n - 1]).
int queryIntervalLengths(int i) const {
return query(treeIntervalLengths, 0, 0, n - 1, i, n - 1);
}
private:
const int n;
vector<int> treeIntervalCounts;
vector<int> treeIntervalLengths;
void add(int treeIndex, int lo, int hi, int i, int val) {
if (lo == hi) {
treeIntervalCounts[treeIndex] += val;
treeIntervalLengths[treeIndex] = treeIntervalCounts[treeIndex] * i;
return;
}
const int mid = (lo + hi) / 2;
if (i <= mid)
add(2 * treeIndex + 1, lo, mid, i, val);
else
add(2 * treeIndex + 2, mid + 1, hi, i, val);
treeIntervalCounts[treeIndex] =
merge(treeIntervalCounts[2 * treeIndex + 1],
treeIntervalCounts[2 * treeIndex + 2]);
treeIntervalLengths[treeIndex] =
merge(treeIntervalLengths[2 * treeIndex + 1],
treeIntervalLengths[2 * treeIndex + 2]);
}
int query(const vector<int>& tree, int treeIndex, int lo, int hi, int i,
int j) const {
if (i <= lo && hi <= j) // [lo, hi] lies completely inside [i, j].
return tree[treeIndex];
if (j < lo || hi < i) // [lo, hi] lies completely outside [i, j].
return 0;
const int mid = (lo + hi) / 2;
return merge(query(tree, treeIndex * 2 + 1, lo, mid, i, j),
query(tree, treeIndex * 2 + 2, mid + 1, hi, i, j));
}
int merge(int left, int right) const {
return left + right;
}
};
class Solution {
public:
vector<int> numberOfAlternatingGroups(vector<int>& colors,
vector<vector<int>>& queries) {
const int n = colors.size();
vector<int> ans;
vector<int> arr{colors};
SegmentTree tree(2 * n - 1);
set<pair<int, int>> intervals;
arr.insert(arr.end(), colors.begin(), colors.end());
// Insert all intervals, each of them is an alternating sequence.
int start = 0;
for (int i = 1; i < 2 * n - 1; ++i)
if (arr[i] == arr[i - 1]) {
insert(intervals, {start, i - 1}, tree, n);
start = i;
}
insert(intervals, {start, 2 * n - 2}, tree, n);
for (const vector<int>& query : queries)
if (query[0] == 1) {
const int sz = query[1];
const pair<int, int>& intervalWithN = findInterval(intervals, n);
const int numAlternatingGroups =
getNumAlternatingGroups(sz, intervalWithN, tree, n);
ans.push_back(numAlternatingGroups);
} else {
const int index = query[1];
const int color = query[2];
if (arr[index] == color)
continue;
update(intervals, index, color, arr, tree, n);
if (index < n - 1)
update(intervals, index + n, color, arr, tree, n);
}
return ans;
}
private:
// Returns the number of alternating groups of size `sz`.
int getNumAlternatingGroups(int sz, const pair<int, int>& intervalWithN,
const SegmentTree& tree, int n) {
const int numIntervals = tree.queryIntervalCounts(sz);
const int sumIntervals = tree.queryIntervalLengths(sz);
// The number of alternating groups for an interval is |interval| - sz + 1.
// Therefore, the number of alternating groups for all intervals is
// sum(|intervals[i]| - sz + 1)
// = sum(|intervals[i]) - numIntervals * sz + numIntervals
const int numAlternatingGroups =
sumIntervals - numIntervals * sz + numIntervals;
// We need to check if the interval (l, r) contains n, and if it does, we
// need to adjust the number of alternating groups to avoid duplicates.
const auto& [l, r] = intervalWithN;
// 1. For an interval with l >= n, it wasn't being considered in `insert`
// and `remove`.
// 2. For an interval with r - l + 1 < sz, it's impossible to form a group
// of size `sz`.
if (l >= n || r - l + 1 < sz)
return numAlternatingGroups;
// 3. For an interval with r >= n, it's possible to duplicately count the
// groups starting from n.
if (r >= n) { // l < n && r - 1 + 1 >= sz
// Groups starting from [l..n) are non-duplicately counted.
const int nonDuplicateGroups = n - l;
// The number of groups of size `sz` in the interval [l..r].
const int numGroups = (r - l + 1) - sz + 1;
return numAlternatingGroups - max(0, numGroups - nonDuplicateGroups);
}
return numAlternatingGroups;
}
// Inserts an interval into `intervals` and updates `tree`.
void insert(set<pair<int, int>>& intervals, const pair<int, int>& interval,
SegmentTree& tree, int n) {
intervals.insert(interval);
if (interval.first < n)
tree.add(interval.second - interval.first + 1, 1);
}
// Removes an interval from `intervals` and updates `tree`.
void remove(set<pair<int, int>>& intervals, const pair<int, int>& interval,
SegmentTree& tree, int n) {
intervals.erase(interval);
if (interval.first < n)
tree.add(interval.second - interval.first + 1, -1);
}
// Returns the interval containing the target.
pair<int, int> findInterval(const set<pair<int, int>>& intervals,
int target) {
auto it = intervals.upper_bound({target, INT_MAX});
return (*--it);
}
// Updates the color of the index-th element in `arr` and updates `intervals`
// and `tree`.
void update(set<pair<int, int>>& intervals, int index, int color,
vector<int>& arr, SegmentTree& tree, int n) {
arr[index] = color;
const pair<int, int> intervalWithIndex = findInterval(intervals, index);
remove(intervals, intervalWithIndex, tree, n);
auto [start, end] = intervalWithIndex;
// interval [s..i - 1|i|i + 1..e]
// index ^
if (start < index && index < end) {
insert(intervals, {start, index - 1}, tree, n);
insert(intervals, {index, index}, tree, n);
insert(intervals, {index + 1, end}, tree, n);
return;
}
// interval [s|s + 1..e]
// index ^
if (start == index && index < end)
insert(intervals, {start + 1, end}, tree, n);
// interval [s..e - 1|e]
// index ^
if (start < index && index == end)
insert(intervals, {start, end - 1}, tree, n);
start = index;
end = index;
vector<pair<int, int>> intervalsToRemove;
auto it = intervals.upper_bound({index, INT_MAX});
for (auto lit = it; lit != intervals.begin();) {
--lit;
if (arr[lit->second] == arr[start]) // [..lit->second|start..]
break;
intervalsToRemove.push_back(*lit);
start = lit->first;
}
for (auto rit = it; rit != intervals.end(); ++rit) {
if (arr[rit->first] == arr[end]) // [..end|rit->first..]
break;
intervalsToRemove.push_back(*rit);
end = rit->second;
}
for (const pair<int, int>& interval : intervalsToRemove)
remove(intervals, interval, tree, n);
insert(intervals, {start, end}, tree, n);
}
};
/* code provided by PROGIEZ */
3245. Alternating Groups III LeetCode Solution in Java
N/A
// code provided by PROGIEZ
3245. Alternating Groups III LeetCode Solution in Python
N/A
# code by PROGIEZ
Additional Resources
- Explore all LeetCode problem solutions at Progiez here
- Explore all problems on LeetCode website here
Happy Coding! Keep following PROGIEZ for more updates and solutions.