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

news/2024/9/15 23:17:36/ 标签: java, 开发语言

将 x 减到 0 的最小操作数

  • 将 x 减到 0 的最小操作数
    • 题目
    • 思路讲解
    • 代码书写

将 x 减到 0 的最小操作数

题目

题目链接: 将 x 减到 0 的最小操作数

思路讲解

按照题目的思路去做这一题是非常恶心的, 因此我们采用正难则反思路. 将问题转换为: 求中间某一个最长的数组长度, 使其和为sum - x, 其中 sum 是数组中所有数的总和

那么此时这个题目就被我们转换为了这一题的类似题目: 长度最小的子数组. 他这里是求长度最小的大于等于的, 我们这里就是求长度最大的只能等于的, 那么这一题是否也能用滑动窗口呢? 我们需要进行暴力优化看看

首先我们的暴力思路就是, 枚举所有子数组, 看看什么时候和为 target = sum - x, 并且找出长度最大值.

在这里插入图片描述

那此时有一个问题, 如果我的 target = 1, 此时遇到了下面的这个情况, 还有没有必要后走?

在这里插入图片描述

很明显没有必要了, 你这个时候区间里面的和都 > 1了, 你再往后加那就还更大, 怎么可能等于 target 呢? 当然这里依旧是由于本题有正整数的性质, 因此是可以这样优化的.

所以我们首先可以知道的是, right 是不一定要遍历完的, 当总和比 target 大后, 就可以直接停了.

接下来就是下一个问题, right 有没有必要回到 left 再次遍历呢? 我们依旧是看例子

在这里插入图片描述

当然也是没有必要的, 因为你要求区间里面的和至少要 target. 你刚刚区间, 就恰好是 >= target 的边界. 也就是说, 左边的值应该都是 <= target 的, 也就是下面这个图蓝色区间的和, 肯定是小于 target 的. 因为是正好加了右侧指针的值才 >= target 停下的

!在这里插入图片描述

那你这个时候, 回去重新走一次, 这不是有病吗? 你肯定还是要走回到 4 这个位置的, 那你回去干什么呢? 因此我们可以推断出, left 和 right 是可以同向移动的, 那么就是经典的滑动窗口问题

因此我们还是老套路, 进行三步走

  1. 进窗口: 很明显, 我们需要将 right 指向的值放入到 sum 里进行维护

  2. 条件判断 + 出窗口: 出窗口, 主要就是 sum 太大了, 就需要出窗口, 出到 sum <= target 的时候就可以了.

  3. 更新结果: 结果的更新, 可以说是最好写的一个部分, 你要什么, 你就在什么时候更新. 我们要的是 sum = target 的长度, 那我们就在 sum = target 的时候更新长度不就行了?

    当然, 更新结果的难点在于你把他放哪, 我们这里是在条件判断走完的时候, 才可能遇到 sum == target 的情况, 因此就在那里更新即可.

但是这个题看似简单, 实际上有非常多的细节问题, 还是非常恶心的, 我们依次来看

  1. 如果刚开始算出 target < 0, 那么此时我们要在一个正整数数组里面找小于 0 的区间, 肯定不可能, 直接返回. 如果不返回, 中间会因为 sum 恒大于 target 从而导致 left 一直出窗口, 最后越界

    此时可能有人问了, target = 0 呢? 实际上这个是合理的, 我们找一个区间, 一个数字都不包含, 那不就是 0 了吗, 因此这个是合理的. 但此时又引出了一个细节问题

  2. 我们要找一个区间, 一个数字都不包含, 此时要求区间长度是 0, 那么我们能用 right - left + 1 这个算法来算长度吗? 很明显就不行了, 我们只能使用 right - left, 并且由于这个设定, 我们的更新结果, 必须放在 right++ 的后面.

    如果不放在 right++ 的后面会导致一个什么问题?

    假设数组里面只有一个 1, target = 0. 也就是我需要找一个长度为 0 的区间. 此时 left 会先到外面, 而 right 还指向着 1 这个数字

    在这里插入图片描述

    此时很明显是不合理的, 而此时我们就需要等 right 出来后, 移动一下, 随后我们就可以进行计算了.

    假如使用的是 right - left + 1, 此时还正好就可以处理掉这种情况, 因为 + 1 相当于直接替代了 right 的一次 ++, 也不会出现问题.

  3. 中间的 length 我们可以赋值一个非法值, 例如 -1. 因为如果找不到等于 target 的区间, 那么最后我们需要返回 -1. 如果设定为 0 的话, 由于 0 是合法的, 我们不能确定这个 0 是不是正确的结果. 因此设定一个非法值方便我们判断.

  4. 我们求出的最大长度并不是答案, 而是我们通过思路转换后的目标值, 题目要求的是最小个数, 因此我们要用数组长度 - 目标值, 就可以得到最终答案了. 正难则反虽然好, 但是如果忘记了把结果也反过来, 那就白搭.

代码书写

java">class Solution {public int minOperations(int[] nums, int x) {// 先求 targetint n = nums.length, numSum = 0;for(int i = 0; i < n; i++) numSum += nums[i];int target = numSum - x;System.out.println(target);if(target < 0) return -1;// 滑动窗口int sum = 0, length = -1, left = 0, right = 0;while(right < n){// 进窗口sum += nums[right];// 条件判断 + 出窗口while(sum > target){sum -= nums[left++];}right++;// 更新结果if(sum == target) length = Math.max(length, right - left);}// 返回结果记得取反, 同时注意细节问题return length == -1 ? length : n - length;}
}

如果有人的思路是在出窗口的时候更新结果, 那么大概率代码如下

java">while(right < n){// 进窗口sum += nums[right];// 条件判断 + 出窗口while(sum >= target){// 更新结果if(sum == target) length = Math.max(length, right - left + 1);sum -= nums[left++];}right++;
}

此时我们只需要一个非常简单而又极端的例子就可以告诉你为什么这样不行, 假设数组里面只有一个 1, target = 0. 也就是我需要找一个长度为 0 的区间.

那么首先我的 left 就会指向 1, 然后出窗口到数组外面, 此时由于 sum == target, 循环继续, 并且此时会更新结果, 但很明显此时再进行出窗口, 就直接越界了.

因此我们的循环条件, 就不能包含等于的情况, 因为在找 target = 0 的时候, 会在sum = 0, 即 left 和 right 在同一个位置的时候还继续出窗口, 导致越界.


http://www.ppmy.cn/news/1520293.html

相关文章

监控Nginx负载均衡后端服务器状态的策略与实践

在Nginx负载均衡的部署中&#xff0c;监控后端服务器的状态对于确保高可用性和服务连续性至关重要。通过检测后端服务器的状态&#xff0c;可以及时发现问题并采取措施&#xff0c;如故障转移或服务重启。本文将详细介绍如何检测Nginx负载均衡后端服务器的状态&#xff0c;包括…

PHP之 ThinkPHP5配置redis缓存

tp config.php cache > [// 使用复合缓存类型type > complex,// 默认使用的缓存default > [// 驱动方式type > File,// 缓存保存目录path > CACHE_PATH,// 缓存前缀prefix > ,// 缓存有效期 0表示永久缓存expire > 0,],// 文件缓存file >…

Prometheus+Grafana监控数据可视化

上一篇文章讲了prometheus的简单使用&#xff0c;这一篇就先跳过中间略显枯燥的内容&#xff0c;来到监控数据可视化。 一方面&#xff0c;可视化的界面看着更带劲&#xff0c;另一方面&#xff0c;也更方便我们直观的查看监控数据&#xff0c;方便后面的学习。 Grafana安装与…

RDP最小化之后仍然保持UI渲染的方法

RDP最小化之后仍然保持UI渲染的方法 1、运行regedit 2、找到注册表项HKEY_CURRENT_USER\Software\Microsoft\TerminalServer Client 3、新建一个类型为DWORD的注册表项RemoteDesktop_SuppressWhenMinimized并设置值为2 4、然后找到注册表项HKEY_CURRENT_USER\Software\Wow6432N…

【Rust光年纪】探索Rust嵌入式开发利器:从硬件访问到USB绑定

Rust硬件访问库全面比较&#xff1a;选择最适合你的工具 前言 随着物联网和嵌入式系统的普及&#xff0c;对于树莓派等硬件设备的访问需求逐渐增加。在Rust语言领域&#xff0c;为了满足这一需求&#xff0c;出现了一系列针对树莓派和嵌入式设备的硬件访问库。本文将介绍其中…

代码随想录算法训练营第六十二天 | 图论part11

97. 小明逛公园 #include <iostream> #include <vector> #include <climits> #include <fstream>using namespace std;void floyd(vector<vector<vector<int>>>& grid) {int n grid.size() - 1;for (int k 1; k < n; k) {…

【傅里叶分析】复数基础知识

【傅里叶分析】复数基础知识 复数复数的几何意义与点的对应与向量的对应 复数与极坐标辐角与辐角主值三角函数 参考文献 本文参考了网上的其他文章&#xff0c;已在文末参考文献中列出&#xff1b;如有侵权&#xff0c;请联系我删除。 复变函数是傅里叶分析的基础&#xff0c;而…

鸿蒙(API 12 Beta6版)图形【过度绘制调试使用指导】方舟2D图形服务

当应用页面布局的嵌套程度过深时&#xff0c;应用渲染阶段会存在一些组件的绘制指令被其他组件的绘制指令部分或完全覆盖遮挡的情况&#xff0c;造成冗余的cpu、gpu等计算资源的使用。这种一个屏幕上的像素点被重复绘制了多次的情况被称为过度绘制&#xff08;Overdraw&#xf…

使用cURL探索WebSocket连接的奥秘

更多内容访问个人网站&#xff1a;孔乙己大叔 在现代Web开发中&#xff0c;实时通信已经成为不可或缺的一部分。WebSocket协议因其能够提供低延迟、全双工的通信能力&#xff0c;而被广泛应用于各种实时应用场景中&#xff0c;如在线聊天、实时通知、游戏等。虽然WebSocket主要…

什么软件可以用平板远程控制电脑?

在当今快节奏的工作和生活中&#xff0c;使用平板远程控制电脑已成为一种便捷高效的办公方式。无论你是想随时随地访问办公室的电脑&#xff0c;还是需要在旅途中进行紧急工作任务&#xff0c;Splashtop都是你的不二选择。本文将介绍如何使用Splashtop通过平板远程控制电脑&…

【docker】docker 镜像仓库的管理

Docker 仓库&#xff08; Docker Registry &#xff09; 是用于存储和分发 Docker 镜像的集中式存储库。 它就像是一个大型的镜像仓库&#xff0c;开发者可以将自己创建的 Docker 镜像推送到仓库中&#xff0c;也可以从仓库中拉取所需的镜像。 Docker 仓库可以分为公共仓…

工业软件架构5:(QT和C++实现)

工业软件架构 - 事件驱动 - 5 设计思路任务类的实现任务控制器主程序运行原理扩展功能总结非for循环任务任务分解与状态管理实现思路任务类的实现任务控制器主程序运行原理扩展功能总结 耗时任务继续运行 在一些复杂的系统中&#xff0c;任务需要暂停和继续运行功能。 实现带有…

mysql 八股文

目录 重点 悲观锁和乐观锁的怎么实现 聚簇索引与非聚簇索引区别 Btree 与 B-tree区别 如何计算一个表能存多少数据 基础 数据库的三范式是什么 InnoDB和MyISAM的区别 说一下 ACID 是什么&#xff1f; Select 语句完整的执行顺序 什么情况下mysql会索引失效 Mysql的…

Flask的secret_key作用

app = Flask(__name__) app.secret_key = your_secret_keyapp.secret_key 在 Flask 应用中扮演了非常重要的角色,它用于保护和加密敏感的会话数据和防范某些类型的攻击。下面是 secret_key 的主要作用和相关解释: 1. 加密会话数据 Flask 使用 secret_key 来对会话数据进行签…

gateway的学习

1.网关的作用 1.负载均衡 2.过滤器的使用 1.通过配置文件实现的过滤器 2.代码逻辑层面实现全局过滤器 //全局过滤器代码逻辑实现 Component //Order(1):注解配置过滤器的执行顺序 public class GlobalFilter implements GatewayFilter, Ordered {/*** 处理当前请求&#xff0c;…

axios设置responseType: ‘blob‘,获取接口返回的错误信息

在axios的请求中当后端接口返回的是文件流的情况下&#xff0c;我们需要在请求参数里面设置responseType: blob&#xff0c;如果接口报错&#xff0c;默认前端无法获取后端返回的错误信息。 解决方法&#xff1a;通过FileReader获取错误信息 async handleFetch() {const res aw…

Anaconda的包管理

使用pip命令安装第三方包的方法&#xff0c;其中package-name代表程序包的名字 pip install package-name使用conda下载Python程序包 conda install package-name使用conda list可以查看有哪些包是使用conda进行安装的。 使用pip list可以查看有哪些包是使用pip进行安装的。

Lua中大量注释后取消

在Lua中注释掉一些调试的代码之后&#xff0c;逐个去取消掉又十分耗时麻烦&#xff0c;调试的信息可以像下面这样写&#xff0c; 大量取消的时候可以直接搜索替换。

【STM32】C语言基础补充

学习过程中发现自己好些需要用到的C语言语法、特征都不太熟练了&#xff0c;特意记录一下&#xff0c;免得忘记了&#xff0c;以后遇到了新的也会继续更新 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 目录 1 全局变量 2 结构体 3 静态变量 4 mems…

将军百战死,程序十年成

将军百战死&#xff0c;程序十年成 十年前的 2014.8.3 我释出了动词算子式通用代码生成器的第一个完整版本 InfinityGPGenerator 0.6.5&#xff0c;即无垠式通用代码生成器 0.6.5。这是一个重大的里程碑。十年后&#xff0c;通用代码生成器已经是一个大家族。昨天&#xff0c;…