LeetCode 3356. Zero Array Transformation II
weekly contest 424。
題目
輸入長度 n 的整數陣列 nums,還有二維陣列 queries,其中 queries[i] = [li, ri, vali]。
對於每個 queries[i]:
- 對於 nums 在 [li, ri] 之間的索引至多減少 vali。
- 同一個查詢中,對於不同索引的減少量都是獨立的,不必相同。
一個陣列的所有元素都等於 0,稱做零陣列。
若執行所有操作後能使得 nums 變成零陣列,則回傳 true,否則回傳 false。
在執行前 k 個查詢後,能使得 nums 變成零陣列,求 k 的最小值。
若無法使 nums 變成零陣列,則回傳 -1。
解法
與 Q2 差別在於每個查詢的減少量從 1 變成 [1, val]。差分陣列同樣可以滿足,無所謂。
假設 k 個查詢可以滿足答案,則大於 k 的查詢數必定也合法;若 k 不合法,小於 k 必定也不合法。
答案具有單調性,可以二分答案。
將 Q2 的答案封裝成,做為二分時的判斷邏輯即可。
注意:在 nums 全為 0 時,原本就是零陣列,不需任何查詢。因此下界為 1。
注意 2:執行所有查詢後,可能也無法變成零陣列,因此二分結束後還要檢查答案一次。
時間複雜度 O((N + Q) log Q)。
空間複雜度 O(N)。
class Solution:
def minZeroArray(self, nums: List[int], queries: List[List[int]]) -> int:
N, Q = len(nums), len(queries)
def ok(k):
diff = [0] * (N+5)
for l, r, val in queries[:k]:
diff[l] += val
diff[r+1] -= val
ps = 0
for i in range(N):
ps += diff[i]
if nums[i] > ps:
return False
return True
lo = 0
hi = Q
while lo < hi:
mid = (lo + hi) // 2
if not ok(mid):
lo = mid + 1
else:
hi = mid
if not ok(lo):
return -1
return lo
用內建函數看起來更簡潔。
class Solution:
def minZeroArray(self, nums: List[int], queries: List[List[int]]) -> int:
N, Q = len(nums), len(queries)
def ok(k):
diff = [0] * (N+5)
for l, r, val in queries[:k]:
diff[l] += val
diff[r+1] -= val
return all(x<=y for x, y in zip(nums, accumulate(diff)))
ans = bisect_left(range(Q), True, key=ok)
if not ok(ans):
return -1
return ans