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

【LeetCode】将 x 减到 0 的最小操作数

文章目录

  • 前言
  • 题目描述
  • 算法原理
  • 代码实现


前言

本文探讨了如何找到将数组两端元素之和减到目标值x的最小操作数。通过逆向思维,将问题转化为在数组中间寻找最长子数组,使其和等于总和减x。利用滑动窗口算法高效解决该问题,时间复杂度为O(n)!


题目描述

给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

示例 1:

输入: nums = [1,1,4,2,3], x = 5
输出: 2
解释: 最佳解决方案是移除后两个元素,将 x 减到 0 。

示例 2:

输入: nums = [5,6,7,8,9], x = 4
输出: -1

示例 3:

输入: nums = [3,2,20,1,1,3], x = 10
输出: 5
解释: 最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^4
1 <= x <= 10^9

算法原理

结合给出的示例,题目的意思不难理解,但如果直接按照题目的意思来做这道题,好像有种无从下手的感觉,因为情况太多了,不好处理。

这个时候有人给出了一种解法,非常的巧妙,那就是正难则反,我们可以换个角度来做这道题,那这道题会非常简单(当然这种方法肯定不是我想到的)

题目原来的意思我们可以理解为让我们在数组两边找到最少的元素,让它们的和等于 x,那也就相当于让我们在数组中间找最多的元素,让它们的和等于整个数组的和再减去 x,画图理解:
在这里插入图片描述
如图所示,我们让 a 和 b 区间的和等于 x,等价于让 c 区间的和等于数组所有元素的总和 sum 再减去 x。

根据题目给出的示例,我们发现数组的左右区间是可以为 0 的,所以现在的问题就变成了在数组左右元素中找到一个子数组,让子数组中的和等于一个目标值且数组长度最大,跟我们之前做过的长度最小的子数组那道题很像,那具体我们要这么做呢?

由于题目中的数组元素都是在 1 <= nums[i] <= 10^4 这个区间范围的,即都是大于 0 的,所以我们依然可以用滑动窗口来做这道题。

代码实现

定义两个指针 left 和 right。首先是进窗口,然后是循环的判断、出窗口,循环的过程中,如果区间的和等于目标值即数组元素总和减去 x,就更新一下结果。
代码如下:

class Solution
{
public:int minOperations(vector<int>& nums, int x){int n = nums.size(), left = 0, right = 0, sum = 0, len = -1, target = 0; for (auto& e : nums){target += e;}target = target - x;while (right < n){sum += nums[right++];while (sum > target && left < right){sum -= nums[left++];}if (sum == target){len = max(len, right - left);}}if (len == -1) return -1;return n - len;}
};

这里有个特殊情况要注意一下,那就是我们的目标值是有可能会大于数组元素总和的,这种情况下我们直接返回 -1即可,咱们上边的代码是在循环条件那里加了一个 left < right 的条件判断的,写法不唯一。
如果是要单独判断的话,代码是下面这种:

class Solution {
public:int minOperations(vector<int>& nums, int x) {int sum = 0;for (int a : nums)sum += a;int target = sum - x;// 细节问题if (target < 0)return -1;int ret = -1;for (int left = 0, right = 0, tmp = 0; right < nums.size(); right++) {tmp += nums[right];      // 进窗⼝while (tmp > target)     // 判断tmp -= nums[left++]; // 出窗⼝if (tmp == target)       // 更新结果ret = max(ret, right - left + 1);}if (ret == -1)return ret;elsereturn nums.size() - ret;}
};

两种写法都是可以通过的
在这里插入图片描述


完!

http://www.dtcms.com/a/610372.html

相关文章:

  • Spring Boot 2.7.x 至 2.7.18 及更旧的版本,漏洞说明
  • GEO:抢占AI流量新入口,让品牌成为智能问答中的“标准答案”
  • 钓鱼网站免费空间公司做网站有意义么
  • 单片机超轻量级多任务操作系统实战指南
  • 如何下载各个版本MacOS系统安装包
  • 【Docker安装】Windows10专业版安装教程
  • 等差数列前n项的和
  • 库尔勒市建设路街道办网站邢台网站建设网络优化
  • 网站报301错误重庆妇科医院免费咨询
  • Opengl绘制流程
  • 使用AI来介绍AI
  • 废品回收系统小程序源码
  • 如何选择与使用C++编译器优化开发效率
  • 从“海量文书”到“精准数据”:文档智能抽取重塑车险核心竞争力
  • 【WindowsAPI】 Windows SDK 的包含目录结构
  • Linux环境下的C语言编程(二十二)
  • 网站制作有哪些种类网站建设实训报告作业
  • 运城市网站建设公司发布网站的流程
  • CNN_Demo_20251114
  • 佳易王桌球计时计费管理系统:专注单店数字化运营
  • Rsync:管理员详细指南 第2部分
  • 海康摄像机SDK获取视频流转码显示
  • 事业单位网站登录模板景德镇陶瓷学院校友做网站的
  • 当消防安全遇见数字孪生:一场防患于未“燃”的科技革命
  • Day 43 复习日--Fashion Mnist数据集
  • Android线程池参数配置指南:理论与实战
  • 外贸网站建设科技公司logo是什么意思
  • 手机网站如何排版高端网站建设 恩愉科技
  • 广州手机建设网站小说网站80电子书怎么做
  • S型单级双吸水平中开式离心泵泵轴断裂原因