Skip to content

Commit bd0eb2c

Browse files
committed
feat: update solutions to lc problem: No.3362
1 parent 51a192d commit bd0eb2c

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

solution/3300-3399/3362.Zero Array Transformation III/README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,34 @@ tags:
9797

9898
<!-- solution:start -->
9999

100-
### 方法一:贪心 + 差分数组 + 优先队列(大根堆)
100+
### 方法一:贪心 + 差分数组 + 优先队列
101+
102+
我们希望尽可能多地「移除」区间查询,但又要保证对每个位置 $i$ 来说,被选中、覆盖到它的查询次数 $s(i)$ 至少达到原数组值 $\textit{nums}[i]$,这样才能把该位置的值“减”到 0 或以下。如果对于某个位置 $i$ 无法满足 $s(i)\ge\textit{nums}[i]$,就说明再多选任何查询都不可能让该位置归零,返回 $-1$。
103+
104+
为了做到这一点,我们按查询区间的左端点从小到大遍历,并维护:
105+
106+
1. **差分数组** `d`:用于记录当前已应用的查询在何处分界——当我们在区间 $[l,r]$ 上“应用”一次查询时,立刻在差分数组位置 `d[l] += 1`,并在 `d[r+1] -= 1`,这样在遍历到下标 $i$ 时累加前缀和就能知道有多少次查询覆盖了 $i$。
107+
2. **最大堆** `pq`:存放当前「候选」区间查询的右端点(取负数以便 Python 最小堆模拟最大堆)。为什么选「最晚结束」的区间?因为它能覆盖更远的位置,我们的贪心策略是:**在每个 $i$ 处,只在必要时才摘取堆顶最长的区间来增加一次覆盖**,这样能为后续位置保留更多可用的区间。
108+
109+
具体步骤如下:
110+
111+
1. 先对 `queries` 按左端点 `l` 升序排序;
112+
2. 初始化差分数组 `d` 长度为 `n+1`(用来处理 `r+1` 处的减操作),以及当前覆盖次数 `s=0`、堆指针 `j=0`
113+
3. 从 $i=0$ 遍历到 $n-1$:
114+
115+
- 先把 `d[i]` 累加到 `s`,即时更新已有的覆盖次数;
116+
- 将所有左端点 $\le i$ 的查询 $[l,r]$ 压入最大堆 `pq`(存 `-r`),并推进 `j`
117+
- 当当前覆盖次数 `s` 小于所需值 `nums[i]`,且堆不空且堆顶区间仍能覆盖 $i$(即 $-pq[0]\ge i$)时:
118+
119+
1. 弹出堆顶(最长的区间),等价于“应用”这次查询;
120+
2.`s += 1` 并在 `d[r+1] -= 1`(使得在跨过 `r` 后覆盖次数自动回退);
121+
122+
- 重复上述步骤,直到 `s>=nums[i]` 或无法再选区间;
123+
- 若此时 `s<nums[i]`,说明无法将位置 $i$ 归零,直接返回 $-1$。
124+
125+
4. 全部遍历完毕后,剩在堆里的区间都是「未被弹出」的,也就是真正被**保留**(即未被用来完成“归零”任务)的查询。堆大小即为答案。
126+
127+
时间复杂度 $O(n + m \times \log m)$,空间复杂度 $O(n + m)$,其中 $n$ 是数组的长度,而 $m$ 是查询的个数。
101128

102129
<!-- tabs:start -->
103130

solution/3300-3399/3362.Zero Array Transformation III/README_EN.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,34 @@ tags:
9494

9595
<!-- solution:start -->
9696

97-
### Solution 1
97+
### Solution 1: Greedy + Difference Array + Priority Queue
98+
99+
We want to "remove" as many interval queries as possible, while ensuring that for each position $i$, the number of selected queries covering it, $s(i)$, is at least the original array value $\textit{nums}[i]$, so that the value at that position can be reduced to 0 or below. If for some position $i$ we cannot satisfy $s(i) \ge \textit{nums}[i]$, it means that no matter how many more queries we select, it is impossible to make that position zero, so we return $-1$.
100+
101+
To achieve this, we traverse the queries in order of their left endpoints and maintain:
102+
103+
1. **Difference array** `d`: Used to record where the currently applied queries take effect—when we "apply" a query on the interval $[l, r]$, we immediately do `d[l] += 1` and `d[r+1] -= 1`. This way, when traversing to index $i$, the prefix sum tells us how many queries cover $i$.
104+
2. **Max heap** `pq`: Stores the right endpoints of the current "candidate" interval queries (store as negative numbers to simulate a max heap in Python's min heap). Why choose the "latest ending" interval? Because it can cover farther positions. Our greedy strategy is: **at each $i$, only pick the longest interval from the heap when necessary to increase coverage**, so that more intervals are available for subsequent positions.
105+
106+
The specific steps are as follows:
107+
108+
1. Sort `queries` by the left endpoint `l` in ascending order;
109+
2. Initialize the difference array `d` with length `n+1` (to handle the decrement at `r+1`), and set the current coverage count `s=0`, heap pointer `j=0`;
110+
3. For $i=0$ to $n-1$:
111+
112+
- First, add `d[i]` to `s` to update the current coverage count;
113+
- Push all queries $[l, r]$ with left endpoint $\le i$ into the max heap `pq` (store `-r`), and advance `j`;
114+
- While the current coverage `s` is less than the required value `nums[i]`, and the heap is not empty, and the top interval in the heap still covers $i$ (i.e., $-pq[0] \ge i$):
115+
116+
1. Pop the top of the heap (the longest interval), which is equivalent to "applying" this query;
117+
2. Increment `s` by 1 and do `d[r+1] -= 1` (so that after passing $r$, the coverage count automatically decreases);
118+
119+
- Repeat the above steps until `s \ge nums[i]` or no more intervals can be selected;
120+
- If at this point `s < nums[i]`, it means it is impossible to make position $i$ zero, so return $-1$.
121+
122+
4. After traversing all positions, the intervals remaining in the heap are those that were **not popped**, i.e., the queries that are truly **retained** (not used for the "zeroing" task). The heap size is the answer.
123+
124+
The time complexity is $O(n + m \times \log m)$, and the space complexity is $O(n + m)$, where $n$ is the length of the array and $m$ is the number of queries.
98125

99126
<!-- tabs:start -->
100127

0 commit comments

Comments
 (0)