列表

详情


100388. 交替组 III

给你一个整数数组 colors 和一个二维整数数组 queriescolors表示一个由红色和蓝色瓷砖组成的环,第 i 块瓷砖的颜色为 colors[i] :

环中连续若干块瓷砖的颜色如果是 交替 颜色(也就是说这组瓷砖中除了第一块和最后一块瓷砖以外,中间瓷砖的颜色与它 左边 和 右边 的颜色都不同),那么它被称为一个 交替组

你需要处理两种类型的查询:

返回数组 answer,数组中按顺序包含第一种类型查询的结果。

注意 ,由于 colors 表示一个  ,第一块 瓷砖和 最后一块 瓷砖是相邻的。

 

示例 1:

输入:colors = [0,1,1,0,1], queries = [[2,1,0],[1,4]]

输出:[2]

解释:

第一次查询:

colors[1] 改为 0。

第二次查询:

统计大小为 4 的交替组的数量:

示例 2:

输入:colors = [0,0,1,0,1,1], queries = [[1,3],[2,3,0],[1,5]]

输出:[2,0]

解释:

第一次查询:

统计大小为 3 的交替组的数量。

第二次查询:colors不变。

第三次查询:不存在大小为 5 的交替组。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: vector<int> numberOfAlternatingGroups(vector<int>& colors, vector<vector<int>>& queries) { } };

cpp 解法, 执行用时: 369 ms, 内存消耗: 174.1 MB, 提交时间: 2024-08-10 12:04:24

class FenwickTree {
    vector<array<int, 2>> tree;
public:
    FenwickTree(int n) : tree(n + 1) {}

    // op=1,添加一个 size
    // op=-1,移除一个 size
    void update(int size, int op) {
        for (int i = tree.size() - size; i < tree.size(); i += i & -i) {
            tree[i][0] += op;
            tree[i][1] += op * size;
        }
    }

    // 返回 >= size 的元素个数,元素和
    pair<int, int> query(int size) {
        int cnt = 0, sum = 0;
        for (int i = tree.size() - size; i > 0; i &= i - 1) {
            cnt += tree[i][0];
            sum += tree[i][1];
        }
        return {cnt, sum};
    }
};

class Solution {
public:
    vector<int> numberOfAlternatingGroups(vector<int>& a, vector<vector<int>>& queries) {
        int n = a.size();
        set<int> s;
        FenwickTree t(n);

        // op=1,添加一个结束位置 i
        // op=-1,移除一个结束位置 i
        auto update = [&](int i, int op) {
            auto it = s.lower_bound(i);
            int pre = it == s.begin() ? *s.rbegin() : *prev(it);
            int nxt = it == s.end() ? *s.begin() : *it;

            t.update((nxt - pre + n - 1) % n + 1, -op); // 移除/添加旧长度
            t.update((i - pre + n) % n, op);
            t.update((nxt - i + n) % n, op); // 添加/移除新长度
        };

        // 添加一个结束位置 i
        auto add = [&](int i) {
            if (s.empty()) {
                t.update(n, 1);
            } else {
                update(i, 1);
            }
            s.insert(i);
        };

        // 移除一个结束位置 i
        auto del = [&](int i) {
            s.erase(i);
            if (s.empty()) {
                t.update(n, -1);
            } else {
                update(i, -1);
            }
        };

        for (int i = 0; i < n; i++) {
            if (a[i] == a[(i + 1) % n]) {
                add(i); // i 是一个结束位置
            }
        }

        vector<int> ans;
        for (auto& q : queries) {
            if (q[0] == 1) {
                if (s.empty()) {
                    ans.push_back(n); // 每个长为 size 的子数组都符合要求
                } else {
                    auto [cnt, sum] = t.query(q[1]);
                    ans.push_back(sum - cnt * (q[1] - 1));
                }
            } else {
                int i = q[1];
                if (a[i] == q[2]) { // 无影响
                    continue;
                }
                int pre = (i - 1 + n) % n, nxt = (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 ans;
    }
};

golang 解法, 执行用时: 431 ms, 内存消耗: 15.6 MB, 提交时间: 2024-08-10 12:04:00

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
}

java 解法, 执行用时: 100 ms, 内存消耗: 79.4 MB, 提交时间: 2024-08-10 12:03:45

class FenwickTree {
    private final int[][] t;

    public FenwickTree(int n) {
        t = new int[n + 1][2];
    }

    // op=1,添加一个 size
    // op=-1,移除一个 size
    public void update(int size, int op) {
        for (int i = t.length - size; i < t.length; i += i & -i) {
            t[i][0] += op;
            t[i][1] += op * size;
        }
    }

    // 返回 >= size 的元素个数,元素和
    public int[] query(int size) {
        int cnt = 0, sum = 0;
        for (int i = t.length - size; i > 0; i &= i - 1) {
            cnt += t[i][0];
            sum += t[i][1];
        }
        return new int[]{cnt, sum};
    }
}

class Solution {
    public List<Integer> numberOfAlternatingGroups(int[] a, int[][] queries) {
        int n = a.length;
        TreeSet<Integer> set = new TreeSet<>();
        FenwickTree t = new FenwickTree(n);

        for (int i = 0; i < n; i++) {
            if (a[i] == a[(i + 1) % n]) {
                add(set, t, n, i); // i 是一个结束位置
            }
        }

        List<Integer> ans = new ArrayList<>();
        for (int[] q : queries) {
            if (q[0] == 1) {
                if (set.isEmpty()) {
                    ans.add(n); // 每个长为 size 的子数组都符合要求
                } else {
                    int[] res = t.query(q[1]);
                    ans.add(res[1] - res[0] * (q[1] - 1));
                }
            } else {
                int i = q[1];
                if (a[i] == q[2]) { // 无影响
                    continue;
                }
                int pre = (i - 1 + n) % n;
                int nxt = (i + 1) % n;
                // 修改前,先去掉结束位置
                if (a[pre] == a[i]) {
                    del(set, t, n, pre);
                }
                if (a[i] == a[nxt]) {
                    del(set, t, n, i);
                }
                a[i] ^= 1;
                // 修改后,添加新的结束位置
                if (a[pre] == a[i]) {
                    add(set, t, n, pre);
                }
                if (a[i] == a[nxt]) {
                    add(set, t, n, i);
                }
            }
        }
        return ans;
    }

    // 添加一个结束位置 i
    private void add(TreeSet<Integer> set, FenwickTree t, int n, int i) {
        if (set.isEmpty()) {
            t.update(n, 1);
        } else {
            update(set, t, n, i, 1);
        }
        set.add(i);
    }

    // 移除一个结束位置 i
    private void del(TreeSet<Integer> set, FenwickTree t, int n, int i) {
        set.remove(i);
        if (set.isEmpty()) {
            t.update(n, -1);
        } else {
            update(set, t, n, i, -1);
        }
    }

    // op=1,添加一个结束位置 i
    // op=-1,移除一个结束位置 i
    private void update(TreeSet<Integer> set, FenwickTree t, int n, int i, int op) {
        Integer pre = set.floor(i);
        if (pre == null) {
            pre = set.last();
        }

        Integer nxt = set.ceiling(i);
        if (nxt == null) {
            nxt = set.first();
        }

        t.update((nxt - pre + n - 1) % n + 1, -op); // 移除/添加旧长度
        t.update((i - pre + n) % n, op);
        t.update((nxt - i + n) % n, op); // 添加/移除新长度
    }
}

python3 解法, 执行用时: 1202 ms, 内存消耗: 36.2 MB, 提交时间: 2024-08-10 12:03:31

from sortedcontainers import SortedList

class Solution:
    def numberOfAlternatingGroups(self, a: List[int], queries: List[List[int]]) -> List[int]:
        n = len(a)
        sl = SortedList()
        t = [[0, 0] for _ in range(n + 1)]

        # op=1,添加一个 size
        # op=-1,移除一个 size
        def fenwick_update(size: int, op: int) -> None:
            i = len(t) - size
            while i < len(t):
                t[i][0] += op
                t[i][1] += op * size
                i += i & -i

        # 返回 >= size 的元素个数,元素和
        def fenwick_query(size: int) -> (int, int):
            cnt = s = 0
            i = len(t) - size
            while i > 0:
                cnt += t[i][0]
                s += t[i][1]
                i &= i - 1
            return cnt, s

        # op=1,添加一个结束位置 i
        # op=-1,移除一个结束位置 i
        def update(i: int, op: int) -> None:
            idx = sl.bisect_left(i)
            pre = sl[idx - 1]
            nxt = sl[idx % len(sl)]

            fenwick_update((nxt - pre - 1) % n + 1, -op)  # 移除/添加旧长度
            fenwick_update((i - pre) % n, op)
            fenwick_update((nxt - i) % n, op)  # 添加/移除新长度

        # 添加一个结束位置 i
        def add(i: int) -> None:
            if not sl:
                fenwick_update(n, 1)
            else:
                update(i, 1)
            sl.add(i)

        # 移除一个结束位置 i
        def remove(i: int) -> None:
            sl.remove(i)
            if not sl:
                fenwick_update(n, -1)
            else:
                update(i, -1)

        for i, c in enumerate(a):
            if c == a[(i + 1) % n]:
                add(i)  # i 是一个结束位置

        ans = []
        for q in queries:
            if q[0] == 1:
                if not sl:
                    ans.append(n)  # 每个长为 size 的子数组都符合要求
                else:
                    cnt, s = fenwick_query(q[1])
                    ans.append(s - cnt * (q[1] - 1))
            else:
                i, c = q[1], q[2]
                if a[i] == c:  # 无影响
                    continue
                pre, nxt = (i - 1) % n, (i + 1) % n
                # 修改前,先去掉结束位置
                if a[pre] == a[i]:
                    remove(pre)
                if a[i] == a[nxt]:
                    remove(i)
                a[i] = c
                # 修改后,添加新的结束位置
                if a[pre] == a[i]:
                    add(pre)
                if a[i] == a[nxt]:
                    add(i)
        return ans

python3 解法, 执行用时: 1386 ms, 内存消耗: 36.2 MB, 提交时间: 2024-08-10 12:03:18

from sortedcontainers import SortedList

class FenwickTree:
    def __init__(self, n: int):
        self.t = [[0, 0] for _ in range(n + 1)]

    # op=1,添加一个 size
    # op=-1,移除一个 size
    def update(self, size: int, op: int) -> None:
        i = len(self.t) - size
        while i < len(self.t):
            self.t[i][0] += op
            self.t[i][1] += op * size
            i += i & -i

    # 返回 >= size 的元素个数,元素和
    def query(self, size: int) -> (int, int):
        cnt = s = 0
        i = len(self.t) - size
        while i > 0:
            cnt += self.t[i][0]
            s += self.t[i][1]
            i &= i - 1
        return cnt, s

class Solution:
    def numberOfAlternatingGroups(self, a: List[int], queries: List[List[int]]) -> List[int]:
        n = len(a)
        sl = SortedList()
        t = FenwickTree(n)

        # op=1,添加一个结束位置 i
        # op=-1,移除一个结束位置 i
        def update(i: int, op: int) -> None:
            idx = sl.bisect_left(i)
            pre = sl[idx - 1]
            nxt = sl[idx % len(sl)]

            t.update((nxt - pre - 1) % n + 1, -op)  # 移除/添加旧长度
            t.update((i - pre) % n, op)
            t.update((nxt - i) % n, op)  # 添加/移除新长度

        # 添加一个结束位置 i
        def add(i: int) -> None:
            if not sl:
                t.update(n, 1)
            else:
                update(i, 1)
            sl.add(i)

        # 移除一个结束位置 i
        def remove(i: int) -> None:
            sl.remove(i)
            if not sl:
                t.update(n, -1)
            else:
                update(i, -1)

        for i, c in enumerate(a):
            if c == a[(i + 1) % n]:
                add(i)  # i 是一个结束位置

        ans = []
        for q in queries:
            if q[0] == 1:
                if not sl:
                    ans.append(n)  # 每个长为 size 的子数组都符合要求
                else:
                    cnt, s = t.query(q[1])
                    ans.append(s - cnt * (q[1] - 1))
            else:
                i, c = q[1], q[2]
                if a[i] == c:  # 无影响
                    continue
                pre, nxt = (i - 1) % n, (i + 1) % n
                # 修改前,先去掉结束位置
                if a[pre] == a[i]:
                    remove(pre)
                if a[i] == a[nxt]:
                    remove(i)
                a[i] = c
                # 修改后,添加新的结束位置
                if a[pre] == a[i]:
                    add(pre)
                if a[i] == a[nxt]:
                    add(i)
        return ans

上一题