【滑动窗口】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)

相关推荐
马剑威(威哥爱编程)1 小时前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
算法萌新——12 小时前
洛谷P2240——贪心算法
算法·贪心算法
湖北二师的咸鱼2 小时前
专题:二叉树递归遍历
算法·深度优先
重生之我要进大厂2 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode
Happy鱿鱼3 小时前
C语言-数据结构 有向图拓扑排序TopologicalSort(邻接表存储)
c语言·开发语言·数据结构
KBDYD10103 小时前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法
Crossoads3 小时前
【数据结构】排序算法---桶排序
c语言·开发语言·数据结构·算法·排序算法
自身就是太阳3 小时前
2024蓝桥杯省B好题分析
算法·职场和发展·蓝桥杯
孙小二写代码4 小时前
[leetcode刷题]面试经典150题之1合并两个有序数组(简单)
算法·leetcode·面试
QXH2000004 小时前
数据结构—单链表
c语言·开发语言·数据结构