leetcode每日一题 -- 3362. 零数组变换 III

leetcode每日一题 -- 3362. 零数组变换 III_第1张图片

思路

题意是要找出[最少的区间]使nums数组变为零数组,并且使用的区间可以不连续

  • 我的第一想法是先给区间按照左边界排序(就像区间合并题的准备工作那样)
  • 这样的可以使用最大堆,每次将右区间值最大(也就是区间范围最大)的区间应用到差分数组中
  • 但是,后续如何处理还是不太会,遂看了题解,以下是以题解代码作出的思考

预处理思路是一样的,而后续的处理方式是以nums中每个数字为基准,完成一个核心逻辑后,就判断当前累加值是否能将当前数字清为0

核心逻辑:

贪心+大堆

以i为基准值,将queries以左区间值为标准分为多组,每次插入一组

  • 插入右区间值到大堆中,因为我们要先拿到范围最大的区间

记录一个累加值

  • 类似于之前初始化好差分数组后的计算前缀和
  • 后续使用区间时,也要+1 -- 相当于多了一个区间可以对当前位置操作(-1),而这里的+1就代表了传统差分数组中对左区间+1的操作

接下来就是将有效区间应用到差分数组中,并且处理右区间

  • 有效区间 -- 因为有可能在上个步骤中剩余了区间,导致右区间 < 此时的i
  • 当使用完一个区间后,就把它出队,最终还在大堆中的就是未使用的区间(删除的区间)

代码

class Solution {
public:
    int maxRemoval(vector& nums, vector>& queries) {
        // 最先找到范围大的区间(比较右边界),左边界可以从0开始遍历
        sort(queries.begin(), queries.end(),
             [](const vector& x, const vector& y) {
                 return x[0] < y[0];
             });

        int n = nums.size();
        vector delt_arr(n + 1, 0);
        int op_num = 0;
        priority_queue heap; // 默认大堆

        // 比较当前每一位数字是否可以被减为0
        for (int i = 0, j = 0; i < nums.size(); ++i) {
            // 累加出当前可以被操作的值
            op_num += delt_arr[i];
            // 每次加入左区间为i的数组
            while (j < queries.size() && queries[j][0] == i) {
                heap.push(queries[j][1]);
                ++j;
            }
            // 经大堆排序后,初始化到差分数组中(注意,这里插入的要是有效区间)
            while (op_num < nums[i] && heap.size() > 0 && heap.top() >= i) {
                // 有一个新区间覆盖到当前位置
                op_num++;
                delt_arr[heap.top() + 1]--;
                heap.pop();
            }
            // 所有覆盖到该位的区间都已操作完
            if (op_num < nums[i]) {
                return -1;
            }
        }
        return heap.size();
    }
};

你可能感兴趣的:(#,算法题,leetcode,算法)