当前位置: 首页 > article >正文

LeetCode --- 424周赛

题目列表

3354. 使数组元素等于零

3355. 零数组变换 I

3356. 零数组变换 II

3357. 最小化相邻元素的最大差值

一、使数组元素等于零

这题的本质就是看 nums[i] = 0 的左右两边的子数组和是否相等 / 相差为1,当两边的和相等时,先向左或者先向右都能让整个数组为0,当两边的和相差为1时,先向和较大的一边进行移动,才能让整个数组为0 【如果不太明白建议手动模拟一下】,代码如下

class Solution {
public:
    int countValidSelections(vector<int>& nums) {
        int n = nums.size();
        int suf = accumulate(nums.begin(), nums.end(), 0);
        int pre = 0, ans = 0;
        for(int i = 0; i < n; i++){ // 分别计算前缀和 / 后缀和
            if(nums[i] == 0){
                if(pre == suf) ans += 2;
                else if(abs(pre - suf) == 1) ans++;
            }
            pre += nums[i];
            suf -= nums[i];
        }
        return ans;
    }
};

二、零数组变换I

这题的query涉及对区间进行加减操作,很适合用差分数组来做(可以在O(n)的时间内实现对区间的+/-操作),代码如下

class Solution {
public:
    bool isZeroArray(vector<int>& nums, vector<vector<int>>& q) {
        int n = nums.size(), m = q.size();
        vector<int> diff(n + 1);
        for(auto v: q){
            diff[v[0]]--;
            diff[v[1]+1]++;
        }
        int pre = 0;
        for(int i = 0; i < n; i++){
            pre += diff[i];
            if(pre + nums[i] > 0)
                return false;
        }
        return true;
    }
};

三、零数组变换II

这题作为第二题的进阶,问我们最少顺序执行多少次query,才能让整个数组为0,该问题满足二分条件,我们可以复用第二题的代码作为check函数,代码如下

class Solution {
    using LL = long long;
public:
    int minZeroArray(vector<int>& nums, vector<vector<int>>& queries) {
        int n = nums.size(), m = queries.size();
        auto check = [&](int k)->bool{
            vector<LL> diff(n + 1);
            for(int i = 0; i < k; i++){
                auto v = queries[i];
                diff[v[0]] -= v[2]; // 注意这里是 -v[2],不是 -1,在拷贝第二题代码的时候要注意
                diff[v[1]+1] += v[2];
            }
            LL pre = 0;
            for(int i = 0; i < n; i++){
                pre += diff[i];
                if(pre + nums[i] > 0)
                    return false;
            }
            return true;  
        };
        int l = 0, r = m;
        while(l <= r){
            int mid = l + (r - l)/2;
            if(check(mid)) r = mid - 1;
            else l = mid + 1;
        }
        return l == m + 1 ? -1 : l;
    }
};

这里还有另外一个思路:我们可以边遍历数组,边处理query,即同时维护差分数组和当前元素的操作数(这里操作数表示当前这么多次query后,nums[i]应该被减去的值),具体代码如下

class Solution {
public:
    int minZeroArray(vector<int>& nums, vector<vector<int>>& queries) {
        int n = nums.size(), m = queries.size();
        vector<int> diff(n + 1);
        int j = 0, pre = 0;
        for(int i = 0; i < n; i++){
            pre += diff[i]; // 维护 pre
            while(pre < nums[i] && j < m){
                int l = queries[j][0], r = queries[j][1], val = queries[j][2];
                j++;
                diff[l] += val;
                diff[r+1] -= val;
                if(l <= i && i <= r) // 在这种情况下 pre += diff[i] 无法被执行,所以我们直接修改 pre 即可
                    pre += val;
            }
            if(pre < nums[i]) return -1; // 表示所有query都执行了,也不能让 nums[i] = 0
        }
        return j;
    }
};

四、最小化相邻元素的最大差值

思路如下 

class Solution {
public:
    int minDifference(vector<int>& nums) {
        int n = nums.size();
        int left = INT_MAX, right = INT_MIN;
        for(int i = 0; i < n; i++){
            if(nums[i] > 0 && (i && nums[i-1] == -1 || i + 1 < n && nums[i+1] == -1)){
                left = min(left, nums[i]);
                right = max(right, nums[i]);
            }
        }
        int ans = 0;
        auto updata = [&](int L, int R, bool islimit){
            // 考虑将 -1 划分到 [left, R] 还是 [L, right] 中
            int d = (min(right - L, R - left) + 1) / 2;
            if(islimit) { // 考虑连续的 -1 的情况,d 的上限为 (right - left + 2) / 3
                d = min(d, (right - left + 2) / 3);
            }
            ans = max(ans, d);
        };
        int pre_i = -1;
        for(int i = 0; i < n; i++){
            if(nums[i] > 0){
                if(pre_i >= 0){
                    if(i - pre_i == 1){ // 两个连续的 > 0 的数
                        ans = max(ans, abs(nums[i] - nums[pre_i])); // 跟新答案
                    }else{
                        updata(min(nums[i], nums[pre_i]), max(nums[i], nums[pre_i]), i - pre_i > 2); // i - pre_i > 2 用来判断是否有连续的 -1
                    }
                }else if(i > 0){
                    // 对于 -1 -1 -1 2 这种情况的 -1
                    updata(nums[i], nums[i], false);
                }
                pre_i = i;
            }
        }
        if(0 <= pre_i && pre_i < n - 1){
            // 对于 2 -1 -1 -1 这种情况的 -1
            updata(nums[pre_i], nums[pre_i], false);
        }
        return ans;
    }
};

http://www.kler.cn/a/414614.html

相关文章:

  • 挂载本地目录到k8s的pod实现持久化存储
  • 【数据结构】双向链表、单向循环链表、双向循环链表、栈、链栈
  • 《Vue 数据绑定:开启动态页面之旅》
  • 音视频入门基础:MPEG2-TS专题(8)——TS Header中的适配域
  • liteflow 架构详解
  • List集合的进一步学习:性能优化
  • 光伏功率预测!Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN五模型时序预测
  • Springboot项目搭建(7)-Layout界面布局
  • Vue.js - axios网络请求
  • C/C++ 中volatile 关键字
  • 【DERPNSTINK靶场渗透】
  • [在线实验]-Redis Docker镜像的下载与部署
  • C++中智能指针的使用及其原理 -- RAII,内存泄漏,shared_ptr,unique_ptr,weak_ptr
  • vue安装cypress及其部分用法
  • 基于C#+SQLite开发数据库应用的示例
  • 从传统IT运维到智能化运维的转型之路
  • 数据结构 (10)队列
  • linux基础2
  • 分布式搜索引擎Elasticsearch(一)
  • golang每日一题:context、goroutine相关
  • 【Ubuntu 24.04】How to Install and Use NVM
  • 【算法day2】数组:滑动窗口、前缀和及指针控制
  • 轻松解析 PDF 文档:深入了解 Python 的 pdfplumber 库
  • 原生html+css+ajax+php图片压缩后替换原input=file上传
  • 【配置】pycharm运行的项目如何修改名称(项目名称、模块名称)
  • 【AI系统】分布式通信与 NVLink