【刷题笔记】长度最小的子数组||二分查找||边界||数组

news2024/10/7 13:17:03

长度最小的子数组

1 题目描述

https://leetcode.cn/problems/minimum-size-subarray-sum/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

进阶:如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

2 思路

2.1 整体架构

因为前几天做二分查找做魔怔了,导致我一上来就想着用二分,根本没想到O(n)时间复杂度的双指针法。

👉O(n)时间复杂度的做法

接下来讲述使用O(n log (n))时间复杂度的做法。

在这里插入图片描述

如上图,假设我们有一个子串(黄色部分),黄色子串的总和为Sum,我们可以从黄色子串中寻找一个更小的绿色子串(和为Sum_sub),我们要让这个绿色子串满足Sum - Sum_sub >= target,如果绿色子串尽可能的长,那么黄色子串去除绿色子串之后剩余的子串就尽可能地短。

我们看题目要求,n个正整数,这说明了当我们对每个位置i及其之前的元素进行加和,获得一个新的数组sum_list,那么sum_list[i]>sum_list[i-1],这说明sum_list是一个单调递增数组。

假设我们的黄色数组为nums[0:i+1] (0~i索引对应的元素构成的子串)。我们则需要在nums[0:1]nums[0:i] 这些数组中找到长度最大的并且满足要求的数组nums[0:t+1](索引从0到t的元素构成的数组)。它们满足sum_list[i] - sum_list[t] >= target

翻译一下,其实就是当我们在遍历到i的时候,需要从sum_list[0]~sum_list[i-1]中找到一个索引t,满足sum_list[i] - sum_list[t] >= target,这说明nums[t + 1]~nums[i]的和大于等于target,而sum_list[i] - sum_list[t + 1] < target

即,当最外部索引为i的时候,我们需要从sum_list[0] ~ sum_list[i - 1]中寻找满足sum_list[i] - sum_list[j] >= target的右边界索引t

首先我们计算sum_list

int more_index = -1;
int min_len = nums.length;
int[] sum_list = new int[nums.length];
int sum = 0;
for (int i = 0; i < nums.length; i++) {
    sum += nums[i];
    sum_list[i] = sum;
    if (sum >= target){
        if (more_index < 0) more_index = i;
    }
}
if (more_index == -1) return 0;

此时,more_index是为了记录第一个大于等于target的坐标。因为如果sum_list[i] < target没有意义,不可能在0~i中找到一个大于等于target的子串,因为整个数组全部为正整数。

如果整个数组中没有和能够大于等于target的子串,直接返回0。

假设我们现在已经有了一个二分查找的函数,那么我们如何续写接下来的代码呢?

如果我们已经通过二分查找获得了当前sum_list[0:i]子串(这是python的切片风格,表示从0~(i-1)的子串)中,最后一个满足sum_list[i] - sum_list[j] >= target的下标t,如果没找到,返回-1

如果找到了,那么满足条件的数组长度为i-j,如果返回-1,也照样减去,因为返回-1后,说明只有nums[0:i+1]满足条件,这样的子串的长度是i-(-1) = i+1,也就是说无论返回什么值,我们只需要计算i-j就是满足需求的子串长度了。

接下来我们继续看关键的二分查找部分。

2.2 二分查找设计

这里,我沿用前几篇博客的思路

【刷题笔记】两数之和II_二分法||二分查找||边界||符合思维方式

【刷题笔记】H指数||数组||二分查找的变体

对于二分查找有两个最重要的问题:如何计算mid如何跳转left和right

这个两个问题本身是一个问题,只要我们确定了如何跳转leftright,就能确定如何计算mid。

通过我们上一节的分析,我们知道,这个查找是一个边界问题,查找符合条件的右边界。

left往右移,所以我们用left来找右边界。

在这里插入图片描述

mid满足条件的时候,我们不清楚mid右边的元素是否还满足条件,我们的left最多就是跳转到mid上。

如果mid不满足条件,则说明mid位置对应的元素过大了,mid一定不满足,mid左边还是有可能的。所以right会跳转到mid-1的位置。

我们知道了left会转移到mid上,那么接下来考虑mid的计算。

在这里插入图片描述

众所周知,当我们在只剩下两个元素的时候,mid元素要么是(left + right) / 2,放在left上,要么是(left + right) / 2 + 1,放在right上。

我们已经确定了,left在某些条件下是可能直接跳转到mid上的, 如果让mid=left,下一步如果left需要跳转,left=mid,然后mid=left。。。。。。无限循环。

所以,为了避免死循环,当只有偶数个元素的时候,我们需要让mid跳转到中间两个元素的后一个元素上。所以我说,当我们确定了left和right的跳转问题之后,如何计算mid的问题就迎刃而解。

面对二分问题的时候,left和right的取值,我倾向于直接使用真实位置,即从1开始的位置。
(以上文字也可以在前面给出的博客链接中看到,我期待能够找到一种通用的范式,所以会尽量使用重复文字,不是偷懒😀)

public int biSearch(int other_tar, int[] sumlist, int start, int end) {
    // 参数里面的other_tar其实就是sum_list[i] - target
    // start和end就是需要进行搜索的数组的开始下标和结束下标。
    int left = start + 1, right = end + 1;
    while (left < right) {
        int real_mid = (left + right) / 2 + ((left - right + 1) % 2 == 0 ? 1 : 0);
        // 如果l~r的元素个数为奇数个,(l+r) / 2 就是中间元素的真实位置
        // 如果l-r的元素个数为偶数个,(l+r) / 2 就是中间两个的元素的靠左的元素,所以要+1
        // 变成中间两个元素靠右的位置。
        int mid_index = real_mid - 1; // 索引要比真实位置-1。
        if (sumlist[mid_index] <= other_tar) {
            left = real_mid;
        } else {
            right = real_mid - 1;
        }
    }
    // 看看我们找到的元素是不是真的满足条件,还是说数组中根本没有满足条件的元素
    return (sumlist[left - 1] <= other_tar ? left - 1 : -1); 
}

3 代码

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int more_index = -1;
        int min_len = nums.length;
        int[] sum_list = new int[nums.length];
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            sum_list[i] = sum;
            if (sum >= target){
                if (more_index < 0) more_index = i;
            }
        }
        if (more_index == -1) return 0;
        for (int i = more_index; i < nums.length; i++) {
            int res_pos = biSearch(sum_list[i] - target, sum_list, 0, i - 1);
            min_len = Math.min(i - res_pos, min_len);
        }
        return min_len;
    }

    public int biSearch(int other_tar, int[] sumlist, int start, int end) {
        int left = start + 1, right = end + 1;
        while (left < right) {
            int real_mid = (left + right) / 2 + ((left - right + 1) % 2 == 0 ? 1 : 0);
            int mid_index = real_mid - 1;
            if (sumlist[mid_index] <= other_tar) {
                left = real_mid;
            } else {
                right = real_mid - 1;
            }
        }
        return (sumlist[left - 1] <= other_tar ? left - 1 : -1);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1270697.html

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

相关文章

如何用管理项目的方式管理个人任务

同样一份工作&#xff0c;有的人做起来得心应手&#xff0c;条理清晰&#xff0c;有的人却是手忙脚乱&#xff0c;苦不堪言。在凡事皆项目的时代&#xff0c;用管理项目的方法管理自己的任务&#xff0c;可能会让你的工作事半功倍。 工欲善其事&#xff0c;必先利其器&#xf…

webshell之API免杀

ScriptEngineManager命令执行免杀 ScriptEngineManager执行js代码 利用ScriptEngineManager可以执行js命令&#xff0c;但是由于一般情况下&#xff0c;即便能运行js代码也不一定能执行系统命令。因为一般情况下js执行系统命令主要是依靠两种方式&#xff0c;IE的ActiveX插件…

「幻醒蓝」可视化主题套件|融合天空的清澈与海洋的深邃

现如今&#xff0c;数据可视化已成为信息传递的重要手段之一。在这样一个信息爆炸的时代&#xff0c;向人们传达正确的信息显得尤为重要。为此&#xff0c;可视化主题套件应运而生&#xff0c;提供了一种多样化的、可视化的方式来展示数据。不同的主题套件能够适应不同的信息传…

Springboot如何快速生成分页展示以及统计条数

这是表结构&#xff1a; 前置知识&#xff1a; 分页查询公式&#xff08;&#xff09;&#xff1a; -- 推导一个公式 -- select * from emp -- order by empno -- limit 每页显示记录数 * (第几页-1)&#xff0c;每页显示记录数 统计条数公式&#xff1a; select count…

力扣5.最长回文子串

题目描述 思路 1.能够反复利用已判断好的回文子串 2.当子串s[i1,j-1]是回文子串时&#xff0c;只要s[i]s[j]&#xff0c;那么s[i,j]也会是回文子串 3.用好动态规划&#xff0c;具体解释在代码注释里 代码 class Solution {public String longestPalindrome(String s) {int…

【网络安全】meterpreter攻击实战

1.meterpreter 攻击成功后可以做什么指令&#xff1f; 远程控制命令执行摄像头监控密码获取创建后门用户破坏篡改系统。 2.创建后门用户并开启远程连接&#xff1a; net user zhangsan 123456/add && net localgroup adminstrators zhangsan/add exit run getgul -…

Linux 代码编辑器:vim

vim 编辑器的简介 vi / vim 都是多模式编辑器&#xff0c;不同的是 vim 是 vi 的升级版本&#xff0c;他不仅兼容 vi 的所有指令&#xff0c;而且还有一些新的特性在里面。比如语法高亮&#xff0c;可视化操作不仅可以在终端运行&#xff0c;也可以在 windows&#xff0c;mac …

聊一聊大模型 | 京东云技术团队

事情还得从ChatGPT说起。 2022年12月OpenAI发布了自然语言生成模型ChatGPT&#xff0c;一个可以基于用户输入文本自动生成回答的人工智能体。它有着赶超人类的自然对话程度以及逆天的学识。一时间引爆了整个人工智能界&#xff0c;各大巨头也纷纷跟进发布了自家的大模型&#…

【算法】算法题-20231129

这里写目录标题 一、15. 三数之和二、205. 同构字符串三、383. 赎金信 一、15. 三数之和 提示 中等 6.5K 相关企业 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] …

leetcode 18. 四数之和(优质解法)

代码&#xff1a; class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {List<List<Integer>> listsnew ArrayList<>();int lengthnums.length;Arrays.sort(nums);for(int i0;i<length-4;){for(int ji1;j<lengt…

Oracle--索引

文章目录 一、索引是什么?二、索引的原理三、索引的特征四、创建索引的方式五、怎么确认索引六、案列七、复合索引 一、索引是什么? 索引&#xff08;INDEX&#xff09;是数据库中用于提高查询效率的一种数据结构。它可以加速数据库表的数据查找、过滤和排序等操作。索引是一…

hive创建ES外部表过程中的问题

一、缺少jar包&#xff1a;httpclient 报错&#xff1a; “HiveServer2-Handler-Pool: Thread-696” java.lang.NoClassDefFoundError: org/apache/commons/httpclient/protocol/ProtocolSocketFactory 需要加载commons-httpclient-3.1.jar 二、缺少jar包&#xff1a;eshado…

功率信号源简介及其应用有哪些内容

功率信号源是一种能够提供稳定输出功率信号的设备或电路。它在许多领域中都有广泛的应用。以下是一些关于功率信号源的内容&#xff1a; 功率信号源简介&#xff1a;功率信号源是一种电子设备或电路&#xff0c;它能够提供稳定的输出功率信号。功率信号源通常由放大器、稳压器、…

MATLAB中imbothat函数用法

目录 语法 说明 示例 使用底帽和顶帽滤波增强对比度 imbothat函数的功能是对图像进行底帽滤波。 语法 J imbothat(I,SE) J imbothat(I,nhood) 说明 J imbothat(I,SE) 使用结构元素 SE 对灰度或二值图像 I 执行形态学底帽滤波。底帽滤波计算图像的形态学闭运算&#…

Linux--2.6内核调度和环境变量

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、Linxu2.6内核进程调度队列1、一个CPU拥有一个runqueue2、优先级3、优先级活动队列4、过期…

用纯 CSS 实现网格背景

是不是在日常开发中经常遇到实现网格的需求&#xff0c;网格通常对网页中展示的元素能起到很好的定位和对齐作用。 这里介绍如何只通过 CSS 来实现这个需求&#xff1f; 使用背景图 这里我们的背景图使用 SVG 来创建&#xff0c;首先&#xff0c;创建绘出一个正方形&#xff0c…

学会XPath,轻松抓取网页数据

一、定义 XPath&#xff08;XML Path Language&#xff09;是一种用于在 XML 文档中定位和选择节点的语言。XPath的选择功能非常强大&#xff0c;可以通过简单的路径选择语法&#xff0c;选取文档中的任意节点或节点集。学会XPath&#xff0c;可以轻松抓取网页数据&#xff0c…

机器人仿真之Vrep中Graph功能下的各种曲线问题汇总

vrep&#xff0c;机器人仿真软件大佬&#xff0c;在仿真机械臂轨迹时涉及到末端轨迹的曲线等一系列问题&#xff0c;在不与matlab联合仿真的情况下如何使用vrep获得各种曲线&#xff1f;如何调取Graph表格功能中的各种曲线标题&#xff1f;

系统清理软件CCleaner pro mac功能亮点

CCleaner pro for mac是一款mac系统清理软件。CCleaner pro 主要用来清除mac系统不再使用的垃圾文件&#xff0c;以腾出更多硬盘空间。CCleaner pro下载的另一大功能是清除使用者的上网记录。CCleaner的体积小&#xff0c;运行速度极快&#xff0c;可以对临时文件夹、历史记录、…

three.js--立方体

作者&#xff1a;baekpcyyy&#x1f41f; 使用three.js渲染出可以调节大小的立方体 1.搭建开发环境 1.首先新建文件夹用vsc打开项目终端 2.执行npm init -y 创建配置文件夹 3.执行npm i three0.152 安装three.js依赖 4.执行npm I vite -D 安装 Vite 作为开发依赖 5.根…