【滑动窗口】leetcode1658:将x减到0的最小操作数

目录

一.题目描述

二.思路分析

三.代码编写


一.题目描述

将x减到0的最小操作数

题目要求我们在数组的两端不断地取值,使得取出的数之和等于x,问我们最少需要取几次。

也就是说,在两边取两个区间,使得这两个区间的之和等于x,求这两个区间长度之和最小是多少。

两个区间研究起来比较麻烦,正难则反,我们可以转化为研究两侧区间所围的区间,那么只需找到满足条件的最长区间,这个条件就是区间之和为sum-target(sum是整个数组的和),结果就是数组的长度减去求得的len。

二.思路分析

两层for循环暴力枚举所有的区间,找到符合条件的区间,通过比较得到最长的区间长度,从而得到结果。代码就不具体实现了。

使用滑动窗口优化,首先要证明right不需要回退

right不断向后移动,当移动到图中位置时,区间之和total>= sum-x, right停了下来,(潜台词是[left, right - 1]区间的和是小于total的)。此时应该判断total是否等于sum-x, 如果是就更新结果。隐含条件:。

按照暴力枚举策略 ,left向后移动一步,right回退。但是最终right还是会回到原处。因为图中大括号对应的区间之和是不满足要求的,right会一直向右移动。故right没有必要往回退,留在原地即可。

那么此时的区间之和是否小于sum-x呢?不确定,因为可能跳过的是一个很小的数,区间之和仍然>=sum-x,此时right没有必要向后枚举了,因为区间再往后扩展,和肯定大于sum-x了。所以让left继续向后移动,直到total <sum-x时,right再向后移动。

所以判断是一个循环的逻辑,不能用if简单地只判断一次。

三.代码编写

其中更新结果时total应该等于target,故可以再判断条件成立,出窗口之前判断total是否等于target,如果等于就更新结果。

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum = 0;
        for (auto e : nums)
        {
            sum += e;
        }

        int target = sum - x;

        int n = nums.size();
        int len = -1;
        int left = 0, right = 0;
        int total = 0;//统计窗口内所有数的和
        while (right < n)
        {
            //进窗口
            total += nums[right];

            //判断
            while (total >= target)
            {
                //更新结果
                if (total == target)
                {
                    len = max(len, right - left + 1);
                }
                //出窗口
                total -= nums[left++];
            }

            right++;
        }

        return len == -1 ? -1 : n - len;
    }
};

当你怀着激动的心情提交代码时,发现到第6个用例就挂了

这种错误提示,八成是越界访问了。模拟代码的执行逻辑,最后发现确实是left越界了。原因在于target是个负数,当right移动到n-1位置,left移动到n位置时,total恰好等于0,但还是大于等于target,故还要出窗口,此时left就越界访问报错了。所以targe小于等于0时需要特殊处理。

当target小于0时,直接返回-1,因为所有数都是正整数,不可能有结果。当target=0时,说明sum=x,直接返回数组长度即可。

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum = 0;
        for (auto e : nums)
        {
            sum += e;
        }

        //越界情况单独处理
        int target = sum - x;
        if (target < 0)
        {
            return -1;
        }

        if (target == 0)
        {
            return nums.size();
        }
        
        int n = nums.size();
        int len = -1;
        int left = 0, right = 0;
        int total = 0;//统计窗口内所有数的和
        while (right < n)
        {
            //进窗口
            total += nums[right];

            //判断
            while (total >= target)
            {
                //更新结果
                if (total == target)
                {
                    len = max(len, right - left + 1);
                }
                //出窗口
                total -= nums[left++];
            }

            right++;
        }

        return len == -1 ? -1 : n - len;
    }
};

事实上,还可以将更新结果的操作放在while循环外面,这时只需把循环的条件改为total>target。当程序通过while循环的逻辑后,total要么小于target,要么等于target。此时再进行判断,如果等于就更新结果,这样的逻辑会更加简单,而且此时target=0的情况也不会越界访问了。

cpp 复制代码
class Solution {
public:
    int minOperations(vector<int>& nums, int x) 
    {
        int sum = 0;
        for (auto e : nums)
        {
            sum += e;
        }

        //越界情况单独处理
        int target = sum - x;
        if (target < 0)
        {
            return -1;
        }

        int n = nums.size();
        int len = -1;
        int left = 0, right = 0;
        int total = 0;//统计窗口内所有数的和
        while (right < n)
        {
            //进窗口
            total += nums[right];

            //判断
            while (total > target)
            {
                //出窗口
                total -= nums[left++];
            }
            //更新结果
            if (total == target)
            {
                len = max(len, right - left + 1);
            }

            right++;
        }

        return len == -1 ? -1 : n - len;
    }
};

时间复杂度O(n)

相关推荐
heimeiyingwang9 天前
【深度学习加速探秘】Winograd 卷积算法:让计算效率 “飞” 起来
人工智能·深度学习·算法
时空自由民.9 天前
C++ 不同线程之间传值
开发语言·c++·算法
ai小鬼头9 天前
AIStarter开发者熊哥分享|低成本部署AI项目的实战经验
后端·算法·架构
小白菜3336669 天前
DAY 37 早停策略和模型权重的保存
人工智能·深度学习·算法
zeroporn9 天前
以玄幻小说方式打开深度学习词嵌入算法!! 使用Skip-gram来完成 Word2Vec 词嵌入(Embedding)
人工智能·深度学习·算法·自然语言处理·embedding·word2vec·skip-gram
亮亮爱刷题9 天前
飞往大厂梦之算法提升-7
数据结构·算法·leetcode·动态规划
_周游9 天前
【数据结构】_二叉树OJ第二弹(返回数组的遍历专题)
数据结构·算法
双叶8369 天前
(C语言)Map数组的实现(数据结构)(链表)(指针)
c语言·数据结构·c++·算法·链表·哈希算法
安全系统学习9 天前
【网络安全】DNS 域原理、危害及防御
算法·安全·web安全·网络安全·哈希算法
Cyrus_柯9 天前
C++(面向对象编程——继承)
开发语言·c++·算法·面向对象