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

news2024/11/15 21:37:20

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

代码书写

class Solution {
    public int minOperations(int[] nums, int x) {
        // 先求 target
        int 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;
    }
}

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

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.coloradmin.cn/o/2102778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mybatis搭建,参数传递,增删改查事务管理

1.mybatis概述 原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了 Google Code&#xff0c;随着开发团队转投Google Code 旗下&#xff0c; iBatis3.x正式更名为MyBatis。 MyBatis 是一款优秀的持久层框架。 框架就是对技术的封装&am…

Spring源码之reader、scanner

目录 1.Spring的整体启动流程 2.reader 3.Scanner ApplicationContext的三种加载应用上下文的方式&#xff08;创建Spring容器&#xff09;&#xff1a; AnnotationConfigApplicationContextClassPathXmlApplicationContextFileSystemXmlApplicationContext 1.Spring的整体…

SprinBoot+Vue阅读交流微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平…

观测云核心技术解密:eBPF Tracing 实现原理

前言 eBPF 是一种强大的内核技术&#xff0c;允许在内核中安全地执行自定义代码。通过 eBPF&#xff0c;开发者可以在不修改内核源码的情况下&#xff0c;对内核功能进行扩展和监控。eBPF Tracing 利用这一技术&#xff0c;对系统调用、内核函数等进行跟踪&#xff0c;从而实现…

X86架构(六)——移位指令与无条件转移指令

移位指令 shr 逻辑右移 逻辑右移指令会将操作数连续地向右移动指定的次数&#xff0c;移出的比特被移到标志寄存器的CF位&#xff0c;左边空出来的位置用0填充 ;目的操作数可以是8位或16位的通用寄存器或者内存单元 ;源操作数可以是数字1、8位立即数或者寄存器CL shr r/m8, …

7、Django Admin删除默认应用程序

admin文件 from django.contrib.auth.models import User, Groupadmin.site.unregister(User) admin.site.unregister(Group) 显示效果&#xff1a; 前 后

使用vscode debug cpp/python混合编程的程序(从python调用的C++编译的dll)

使用vscode debug cpp/python混合编程的程序&#xff08;从python调用的C编译的dll&#xff09; 1. 安装插件 Python C Debugger https://marketplace.visualstudio.com/items?itemNamebenjamin-simmonds.pythoncpp-debug 2. 在.vscode/launch.json中增加配置 拷贝自 https:…

K8S日志收集

本章主要讲解在 Kubernetes 集群中如何通过不同的技术栈收集容器的日志&#xff0c;包括程序直接输出到控制台日志、自定义文件日志等。 一、有哪些日志需要收集 为了更加方便的处理异常&#xff0c;日志的收集与分析极为重要&#xff0c;在学习日志收集之前&#xff0c;需要知…

矮草坪渲染尝试

本来说写unity里的&#xff0c;由于three测试方便&#xff0c;先试试three 这个图片是目标效果 可以看见草很矮&#xff0c;很密集&#xff0c;如果用instance来绘制的话&#xff0c;遭不住的 忽然发现这个效果很像绒毛效果 于是找了博客康康 https://zhuanlan.zhihu.com/p/256…

第二证券:涨停潮!传手机将使用钛金属外壳?

今天早盘&#xff0c;银行股再度重挫&#xff0c;导致上证指数、上证50纷乱创出阶段性新低&#xff0c;上证指数跌破2800点&#xff0c;小盘成长股则大面积反弹&#xff0c;创业板指、科创50等股指飘红。 盘面上&#xff0c;新式烟草、钛金属、锂矿、玻璃基板等板块涨幅居前&a…

glsl着色器学习(七)

先了解一个矩阵库twgl/m4 是一个4x4 矩阵数学转换函数的库 normalize(a, dst) 将一个向量除以它的欧几里得长度&#xff0c;归一化后返回参数"a"是一个vec3&#xff08;三维向量&#xff09;参数"dst"是用来接收结果的&#xff0c;如果不传&#xff0c;则…

【嵌入式体系结构复习资料】

选择&#xff1a; 1. 以下哪个不是嵌入式系统设计的主要目标&#xff1f;( D ) A&#xff0e;低成本 B.低功耗 C.实时要求高 D.超高性能 2&#xff0e; 嵌入式系统有别于其他系统的最大特点是&#xff08;A &#xff09;。 A&#xff0e;嵌入专用 B.高可靠 C.…

集成电路学习:什么是LCD液晶显示器

一、LCD&#xff1a;液晶显示器 LCD&#xff0c;全称Liquid Crystal Display&#xff0c;即液晶显示器&#xff0c;是一种平面超薄的显示设备。它由一定数量的彩色或黑白像素组成&#xff0c;放置于光源或者反射面前方。LCD的主要原理是以电流刺激液晶分子产生点、线、面配合背…

mysql 使用 general 开启SQL跟踪功能

查看当前状态 mysql> SHOW VARIABLES LIKE %general%; 启用 临时启用 SET GLOBAL general_logon; SET GLOBAL general_log_file/tmp/general.log; 永久启用 通过修改配置文件来启用,需要重启mysql服务 [mysqld] general_logON general_log_file/tmp/general.log 再次查看状态…

【保姆级教程】如何在Win11上搭建一个GPU环境

CUDA和CUDNN安装 CUDA安装 下载对应cuda环境 下载链接&#xff1a;https://developer.nvidia.com/cuda-downloads&#xff0c;图片下载的是 cuda_12.6.1_560.94_windows.exe 然后一路安装即可&#xff1a; 安装路径如下&#xff1a; CUDNN安装 打开cuDNN下载页面 解压后…

排查SQL Server中的内存不足及其他疑难问题

文章目录 引言I DMV 资源信号灯资源信号灯 DMV sys.dm_exec_query_resource_semaphores( 确定查询执行内存的等待)查询性能计数器什么是内存授予?II DBCC MEMORYSTATUS 查询内存对象III DBCC 命令释放多个 SQL Server 内存缓存 - 临时度量值IV 等待资源池 %ls (%ld)中的内存…

【408DS算法题】034进阶-22年真题_判断顺序存储二叉树是否是BST

Index 真题题目分析实现总结 真题题目 已知非空二叉树T的结点值均为正整数&#xff0c;采用顺序存储方式保存&#xff0c;数据结构定义如下: typedef struct { // MAX_STZE为已定义常量int SqBiTNode[MAX_SIZE]; // 保存二叉树结点值的数组int ElemNum; …

BM3D--Image Denoising by Sparse 3-D Transform-Domain Collaborative Filtering

系列文章目录 文章目录 系列文章目录前言稀疏三维变换域协同滤波图像去噪摘要1 引言2 分组和协作过滤A.分组B.按匹配分组C.协同过滤D.基于变换域收缩的协同过滤 3 算法结论 前言 论文地址 如果下载不了可以从 https://download.csdn.net/download/m0_70420861/89708940 获取 …

Pytorch安装 CUDA Driver、CUDA Runtime、CUDA Toolkit、nvcc、cuDNN解释与辨析

Pytorch的CPU版本与GPU版本 Pytorch的CPU版本 仅在 CPU 上运行&#xff0c;适用于没有显卡或仅使用 CPU 的机器。安装方式相对简单&#xff0c;无需额外配置 CUDA 或 GPU 驱动程序。使用方式与 GPU 版相同&#xff0c;唯一不同的是计算将自动在 CPU 上进行。 Pytorch的GPU版…

VBA学习(63):Excel VBA 数据分析展示/ListView控件/Combox组合框控件/CheckBox复选框控件/科目汇总表

前面我们分享了使用ListVeiw进行数据展示&#xff0c;做出“科目汇总表”来&#xff08;Excel VBA 数据分析展示/ListView控件、Excel VBA 数据分析展示/ListView控件/Combox组合框控件/科目汇总表(2)&#xff09;&#xff0c;今天&#xff0c;我们继续完善按月查询、按一级科目…