【LetMeFly】3362.零數組變換 III:貪心+優先隊列+差分數組——清晰題解
力扣題目鏈接:https://leetcode.cn/problems/zero-array-transformation-iii/
給你一個長度為 n
?的整數數組?nums
?和一個二維數組?queries
?,其中?queries[i] = [li, ri]
?。
每一個?queries[i]
?表示對于 nums
?的以下操作:
- 將
nums
?中下標在范圍?[li, ri]
?之間的每一個元素 最多 減少?1 。 - 坐標范圍內每一個元素減少的值相互 獨立?。
零數組?指的是一個數組里所有元素都等于 0 。
請你返回 最多 可以從 queries
?中刪除多少個元素,使得?queries
?中剩下的元素仍然能將?nums
?變為一個 零數組?。如果無法將 nums
?變為一個 零數組?,返回 -1 。
?
示例 1:
輸入:nums = [2,0,2], queries = [[0,2],[0,2],[1,1]]
輸出:1
解釋:
刪除?queries[2]
?后,nums
?仍然可以變為零數組。
- 對于?
queries[0]
?,將?nums[0]
和?nums[2]
?減少 1 ,將?nums[1]
減少 0 。 - 對于?
queries[1]
?,將?nums[0]
和?nums[2]
?減少?1 ,將?nums[1]
?減少?0 。
示例 2:
輸入:nums = [1,1,1,1], queries = [[1,3],[0,2],[1,3],[1,2]]
輸出:2
解釋:
可以刪除?queries[2]
和?queries[3]
?。
示例 3:
輸入:nums = [1,2,3,4], queries = [[0,3]]
輸出:-1
解釋:
nums
?無法通過 queries
?變成零數組。
?
提示:
1 <= nums.length <= 105
0 <= nums[i] <= 105
1 <= queries.length <= 105
queries[i].length == 2
0 <= li <= ri < nums.length
解題方法:貪心+優先隊列+差分數組
解題思路
我們的目標是盡可能地把每個數都減小到0,可以按nums從左到右依次處理。
對于 n u m s [ 0 ] nums[0] nums[0],在 n u m s [ 0 ] > 0 nums[0]\gt 0 nums[0]>0時,如何選擇query?當然要選擇區間起點為0的query中,區間終點最靠后的那個。
假設選擇了一些query后 n u m s [ 0 ] nums[0] nums[0]變成了 0 0 0(此時 n u m s [ 1 ] nums[1] nums[1]可能也已經減小了一些),開始處理 n u m s [ 1 ] nums[1] nums[1]。道理相同,有限選擇區間起點為1的query中區間終點最靠后的那個。
中間過程中,一旦發生“可選的query無法將 n u m s [ i ] nums[i] nums[i]減小為0的情況”,就返回-1。
具體方法
如何選擇所有可選query中終點最靠后的那個?
我們可以使用一個優先隊列,將所有可選(或曾經可選)的query添加到優先隊列中,優先隊列以query的區間終點最大為最優先。
因此可以先將query按照起點從小到大的順序排個序,遍歷 n u m s [ i ] nums[i] nums[i]的過程中,將query起點為 i i i的query加入優先隊列。
當 n u m s [ i ] nums[i] nums[i]不為 0 0 0時,需要從優先隊列中取出query,如果隊首query的區間終點已經小于 i i i,說明這個query已經無效,沒有可以覆蓋 n u m s [ i ] nums[i] nums[i]的query,不取。
若 n u m s nums nums可以將所有元素減小為 0 0 0,則最終(所有query都將入隊)優先隊列中剩余的query個數記為答案。
取出一個query后,如何將 n u m s [ i ] nums[i] nums[i]到 q u e r y [ 1 ] query[1] query[1]這段區間整個更新(-1)?
可以先做下3355.零數組變換 I,使用差分數組即可將一段區間快速同時減1。
時空復雜度分析
- 時間復雜度 O ( ( m + n ) log ? n ) O((m+n)\log n) O((m+n)logn),其中 m = l e n ( n u m s ) m=len(nums) m=len(nums), n = l e n ( q u e r i e s ) n=len(queries) n=len(queries)
- 空間復雜度 O ( m + n ) O(m+n) O(m+n)
AC代碼
C++
/** @Author: LetMeFly* @Date: 2025-05-24 16:04:04* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-05-24 16:06:59*/
class Solution {
public:int maxRemoval(vector<int>& nums, vector<vector<int>>& queries) {sort(queries.begin(), queries.end());vector<int> diff(nums.size() + 1);priority_queue<int> pq;for (int in = 0, iq = 0, cnt = 0; in < nums.size(); in++) {cnt += diff[in];while (iq < queries.size() && queries[iq][0] == in) {pq.push(queries[iq++][1]);}while (cnt < nums[in] && pq.size() && pq.top() >= in) {cnt++;diff[pq.top() + 1]--;pq.pop();}if (cnt < nums[in]) {return -1;}}return pq.size();}
};
To myself: 二寫和一寫幾乎一模一樣
Python
'''
Author: LetMeFly
Date: 2025-05-23 23:35:45
LastEditors: LetMeFly.xyz
LastEditTime: 2025-05-23 23:52:09
'''
from typing import List
import heapqclass Solution:def maxRemoval(self, nums: List[int], queries: List[List[int]]) -> int:queries.sort()diff = [0] * (len(nums) + 1)cnt = iq = 0pq = []for inum in range(len(nums)):cnt += diff[inum]while iq < len(queries) and queries[iq][0] <= inum:heapq.heappush(pq, -queries[iq][1])iq += 1while cnt < nums[inum] and len(pq) and -pq[0] >= inum:cnt += 1diff[-heapq.heappop(pq) + 1] -= 1if cnt < nums[inum]:return -1return len(pq)
Java
/** @Author: LetMeFly* @Date: 2025-05-23 23:35:45* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-05-23 23:57:57*/
import java.util.Arrays;
import java.util.PriorityQueue;class Solution {public int maxRemoval(int[] nums, int[][] queries) {Arrays.sort(queries, (a, b) -> a[0] - b[0]);int[] diff = new int[nums.length + 1];PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);for (int in = 0, iq = 0, cnt = 0; in < nums.length; in++) {cnt += diff[in];while (iq < queries.length && queries[iq][0] <= in) {pq.add(queries[iq++][1]);}while (cnt < nums[in] && !pq.isEmpty() && pq.peek() >= in) {cnt++;diff[pq.poll() + 1]--;}if (cnt < nums[in]) {return -1;}}return pq.size();}
}
Go
/** @Author: LetMeFly* @Date: 2025-05-23 23:35:45* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-05-24 00:22:47*/
package mainimport ("slices""container/heap"
)func maxRemoval(nums []int, queries [][]int) int {slices.SortFunc(queries, func(a, b []int) int {return a[0] - b[0]})diff := make([]int, len(nums) + 1)pq := &pq3362{}for in, iq, cnt := 0, 0, 0; in < len(nums); in++ {cnt += diff[in]for iq < len(queries) && queries[iq][0] <= in {heap.Push(pq, queries[iq][1])iq++}for cnt < nums[in] && len(*pq) > 0 && (*pq)[0] >= in {cnt++diff[heap.Pop(pq).(int) + 1]--}if cnt < nums[in] {return -1}}return len(*pq)
}type pq3362 []int
func (pq *pq3362) Push(a any) {(*pq) = append((*pq), a.(int))}
func (pq pq3362) Len() int {return len(pq)}
func (pq pq3362) Less(i, j int) bool {return pq[i] > pq[j]}
func (pq pq3362) Swap(i, j int) {pq[i], pq[j] = pq[j], pq[i]}
func (pq *pq3362) Pop() any {a := (*pq)[len(*pq)-1]; (*pq) = (*pq)[:len(*pq)-1]; return a}
同步發文于CSDN和我的個人博客,原創不易,轉載經作者同意后請附上原文鏈接哦~
千篇源碼題解已開源