Leetcode 3362. Zero Array Transformation III
- Leetcode 3362. Zero Array Transformation III
- 1. 解题思路
- 2. 代码实现
- 题目链接:3362. Zero Array Transformation III
1. 解题思路
这一题很可惜没有自力搞定,主要问题还是对于数据结构的了解不够多,像这道题,事实上就是一个使用lazy segment tree的典型题目,只可能我之前并不了解lazy segment tree,因此遇到这道题目就有些无从下手了,不过这也算是查漏补缺了,也挺好的。
这一题和题目3355以及题目3356完全是成套的,显然初始条件显然就是通过一个累积数组即可判断整个数组是否可以被归零。
且通过每一个元素上的可允许操作次数,我们可以得到总的冗余操作次数序列。此时,如果某一个query的范围内全部元素都有冗余操作次数,那么这个query就可以删去。
要使得删去的query尽可能地多,我们只需要将query按照右边界以及长度进行倒序排列,然后逐一进行贪婪考察,显然,当一个query又靠前又短,且其范围内都有冗余,那么即使删掉这个query后面也必然有其他query可以补足,或者之前已经有足够多的必要query将其涵盖了。
剩下的问题就是怎么动态地update这个冗余数组了,这是一个需要实时求范围内的最小值,且需要频繁范围内更新所有元素的值的一个问题,如果只是更新某一个元素,那显然可以用segment tree来进行实现,但是要更新范围内所有元素,就让我有点懵逼了,看了大佬的回答之后发现原来还有一个数据结构叫做lazy segment tree,是说如果时常需要同步更新范围内全部元素的值,那么就可以通过引入一个lazy数组的方式来一次更新整个数组。
关于这部分的内容,后续有时间的话我估计会写个小文章来做个备忘,不过这里就不具体展开了,有兴趣的读者可以自行搜索一下lazy segment tree来了解一下这个数据结构。
2. 代码实现
我们给出python代码实现如下:
class SegmentTree:
def __init__(self, size):
self.n = size
self.tree = [0] * (4 * size)
self.lazy = [0] * (4 * size)
def build(self, cap, node, l, r):
if l == r:
self.tree[node] = cap[l]
return
mid = (l + r) // 2
self.build(cap, 2 * node, l, mid)
self.build(cap, 2 * node + 1, mid + 1, r)
self.tree[node] = min(self.tree[2 * node], self.tree[2 * node + 1])
def down(self, node, l, r):
if self.lazy[node] != 0:
mid = (l + r) // 2
self.tree[2 * node] += self.lazy[node]
self.lazy[2 * node] += self.lazy[node]
self.tree[2 * node + 1] += self.lazy[node]
self.lazy[2 * node + 1] += self.lazy[node]
# Reset lazy value
self.lazy[node] = 0
def update_range(self, node, l, r, ul, ur, delta):
if ul > r or ur < l:
return
if ul <= l and r <= ur:
self.tree[node] += delta
self.lazy[node] += delta
return
self.down(node, l, r)
mid = (l + r) // 2
self.update_range(2 * node, l, mid, ul, ur, delta)
self.update_range(2 * node + 1, mid + 1, r, ul, ur, delta)
self.tree[node] = min(self.tree[2 * node], self.tree[2 * node + 1])
def query(self, node, l, r, ql, qr):
if ql > r or qr < l:
return float('inf')
if ql <= l and r <= qr:
return self.tree[node]
self.down(node, l, r)
mid = (l + r) // 2
return min(self.query(2 * node, l, mid, ql, qr),
self.query(2 * node + 1, mid + 1, r, ql, qr))
class Solution:
def maxRemoval(self, nums: List[int], queries: List[List[int]]) -> int:
queries = sorted(queries, key=lambda x: (x[1], x[0]))
n = len(nums)
cnt = [0 for _ in range(n+1)]
for l, r in queries:
cnt[l] += 1
cnt[r+1] -= 1
cnt = list(accumulate(cnt))
if any(cnt[i] < nums[i] for i in range(n)):
return -1
cap = [cnt[i] - nums[i] for i in range(n)]
st = SegmentTree(n)
st.build(cap, 1, 0, n - 1)
k = 0
for l, r in queries:
curr = st.query(1, 0, n - 1, l, r)
if curr >= 1:
k += 1
st.update_range(1, 0, n - 1, l, r, -1)
return k
提交代码评测得到:耗时5501ms,占用内存60.3MB。