长度最小的子数组[中等]

一、题目

给定一个含有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

::: warning
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
:::

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

二、代码

【1】滑动窗口: 定义两个指针fastslow分别表示子数组(滑动窗口窗口)的开始位置和结束位置,维护变量sum存储子数组中的元素和(即从nums[fast]nums[slow]的元素和)。初始状态下,fastslow都指向下标0sum的值为0。每一轮迭代,将nums[fast]加到 sum,如果sum≥target,则更新子数组的最小长度(此时子数组的长度是fast-slow+1,然后将nums[slow]sum中减去并将start右移,直到sum<target,在此过程中同样更新子数组的最小长度。在每一轮迭代的最后,将fast右移。

class Solution {public int minSubArrayLen(int target, int[] nums) {// 思路:1、指定快慢两个指针 fast slow // 2、fast 先移动,如果 sum > target , slow 先前走一步int fast = 0, slow = 0, sum = 0, min = Integer.MAX_VALUE;while (fast < nums.length) {sum += nums[fast];while (sum >= target) {min = Math.min(min, fast - slow + 1);sum-=nums[slow];++slow;}++fast;}return min == Integer.MAX_VALUE ? 0 : min;}
}

时间复杂度: O(n),其中n是数组的长度。指针fastslow最多各移动n次。
空间复杂度: O(1)

【2】前缀和 + 二分查找: 为了使用二分查找,需要额外创建一个数组sums用于存储数组nums的前缀和,其中sums[i]表示从nums[0]nums[i−1]的元素和。得到前缀和之后,对于每个开始下标i,可通过二分查找得到大于或等于i的最小下标index,使得sums[index]−sums[i−1]≥target,并更新子数组的最小长度(此时子数组的长度是index(i−1))。因为这道题保证了数组中每个元素都为正,所以前缀和一定是递增的,这一点保证了二分的正确性。如果题目没有说明数组中每个元素都为正,这里就不能使用二分来查找这个位置了。

在很多语言中,都有现成的库和函数来为我们实现这里二分查找大于等于某个数的第一个位置的功能,比如C++lower_boundJava中的Arrays.binarySearchC#中的Array.BinarySearchPython中的bisect.bisect_left。但是有时面试官可能会让我们自己实现一个这样的二分查找函数。

class Solution {public int minSubArrayLen(int target, int[] nums) {
return min == Integer.MAX_VALUE ? 0 : min;// 思路:1、新创建一个数组,保存i之前数据和;// 2、根据二分查找,获取到大于target的第一个下标;int[] sums = new int[nums.length + 1];int min = Integer.MAX_VALUE;for (int i = 1; i <= nums.length; i++) {sums[i] = sums[i - 1] + nums[i - 1];}for (int i = 1; i <= nums.length; i++) {int tarTemp = sums[i - 1] + target;int index = Arrays.binarySearch(sums, tarTemp);if (index < 0) {index = -index - 1;}// 找到了if (index <= nums.length) {min = Math.min(min, index - (i - 1));}}return min == Integer.MAX_VALUE ? 0 : min;}
}

时间复杂度: O(nlog⁡n),其中n是数组的长度。需要遍历每个下标作为子数组的开始下标,遍历的时间复杂度是O(n),对于每个开始下标,需要通过二分查找得到长度最小的子数组,二分查找得时间复杂度是O(log⁡n),因此总时间复杂度是O(nlog⁡n)
空间复杂度: O(n),其中n是数组的长度。额外创建数组sums存储前缀和。

【3】暴力解法: 初始化子数组的最小长度为无穷大,枚举数组nums中的每个下标作为子数组的开始下标,对于每个开始下标i,需要找到大于或等于i的最小下标j,使得从nums[i]nums[j]的元素和大于或等于s,并更新子数组的最小长度(此时子数组的长度是j−i+1)。

class Solution {public int minSubArrayLen(int target, int[] nums) {// 思路:1、定义返回值 res = max, 在循环中获取符合要求的最小长度,存入res中。求最小数时,返回值默认时 Integer的最大值;// 2、第一层for循环保证所有的数据都能够被遍历依次,作为left指针// 3、第二层for循环中,遍历left后的元素,找到第一个符合要求的子数组,也就是最小长度的子数组,直接退出;int res = Integer.MAX_VALUE;for(int i = 0; i < nums.length; i++) {// 第一层遍历之前需要重新定义int sum = 0;for(int j = i; j < nums.length; j++) {sum += nums[j];if (sum >= target) {res = Math.min(res, j - i + 1);break;}}}return res == Integer.MAX_VALUE ? 0 : res;}
}

时间复杂度: O(n2),其中n是数组的长度。需要遍历每个下标作为子数组的开始下标,对于每个开始下标,需要遍历其后面的下标得到长度最小的子数组。
空间复杂度: O(1)

【4】使用队列相加(实际上我们也可以把它称作是滑动窗口,这里的队列其实就相当于一个窗口): 我们把数组中的元素不停的入队,直到总和大于等于s为止,接着记录下队列中元素的个数,然后再不停的出队,直到队列中元素的和小于s为止(如果不小于s,也要记录下队列中元素的个数,这个个数其实就是不小于s的连续子数组长度,我们要记录最小的即可)。接着再把数组中的元素添加到队列中……重复上面的操作,直到数组中的元素全部使用完为止。
这里以[2,3,1,2,4,3]举例画个图来看下

上面画的是使用队列,但在代码中我们不直接使用队列,我们使用两个指针,一个指向队头一个指向队尾,我们来看下代码

public int minSubArrayLen(int s, int[] nums) {int lo = 0, hi = 0, sum = 0, min = Integer.MAX_VALUE;while (hi < nums.length) {sum += nums[hi++];while (sum >= s) {min = Math.min(min, hi - lo);sum -= nums[lo++];}}return min == Integer.MAX_VALUE ? 0 : min;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C 练习实例51-学习使用按位与

按位与、或、异或 1.按位与 & 0&00 0&10 1&00 1&11 2.按位或 | 0|00 0|11 1|01 1|11 3.按位异或 ^ 0^00 0^11 1^01 1^10 (只要学过离散数学懂的都懂) &#xff08;都是双目运…

Qt QScrollArea 不显示滚动条 不滚动

使用QScrollArea时&#xff0c;发现添加的控件超出QScrollArea 并没有显示&#xff0c;且没有滚动条效果 原因是 scrollArea指的是scrollArea控件本身的大小&#xff0c;肉眼能看到的外形尺寸。 scrollAreaWidgetContents指的是scrollArea控件内部的显示区域&#xff0c;里面可…

如何优雅的完成权限认证?-- 瞎扯文

文章目录 前言常规解决方案Linux系统文件的权限编码压缩Python版本Java版本总结前言 以前挺喜欢计算机的,出来工作后发现,现在更喜欢了嘿嘿~当然也是沉寂了一个月之久。终于又来冒泡了,实属不易啊。消失了这么久的时间,干嘛去了呢?很简单实习去了,当然不是某互联网公司哈…

05 SB3之Spring Initializr+运行方式+自动配置原理(TBD)

1. 使用IDEA内置Spring Initializr 生成SB项目 最上方Server URL可以选择借助哪个平台生成, 可选阿里云 作为对比 , 官方可选版本最旧为3.1.18 ; 阿里云可选最新版本为3.0.2 本次选择3.1.8版本, 并且添加Spring Web依赖(包括RESTful / Spring MVC/)和Lombok依赖 生成后端项目…

Android Studio项目——TCP客户端

目录 一、TCP客户端UI 1、UI展示 2、xml代码 二、TCP客户端数据发送 三、TCP客户端数据接收 一、TCP客户端UI 1、UI展示 2、xml代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.…

HiveSQL题——窗口函数(lag/lead)

目录 一、窗口函数的知识点 1.1 窗户函数的定义 1.2 窗户函数的语法 1.3 窗口函数分类 1.4 前后函数:lag/lead 二、实际案例 2.1 股票的波峰波谷 0 问题描述 1 数据准备 2 数据分析 3 小结 2.2 前后列转换&#xff08;面试题&#xff09; 0 问题描述 1 数据准备 …

Linux——Ubuntu安装MySQL并设置远程登录

1、安装mysql8.0.35 1.更新包列表&#xff0c;首先&#xff0c;确保您的系统已更新到最新状态。运行以下命令来更新包列表和安装最新的软件包&#xff1a; sudo apt update sudo apt upgrade2.安装MySQL服务器&#xff1a;运行以下命令来安装MySQL服务器&#xff1a; sudo a…

【论文阅读】Long-Tailed Recognition via Weight Balancing(CVPR2022)附MaxNorm的代码

目录 论文使用方法weight decayMaxNorm 如果使用原来的代码报错的可以看下面这个 论文 问题&#xff1a;真实世界中普遍存在长尾识别问题&#xff0c;朴素训练产生的模型在更高准确率方面偏向于普通类&#xff0c;导致稀有的类别准确率偏低。 key:解决LTR的关键是平衡各方面&a…

iOS App审核状态和审核时间管理指

引言 对于一款开发完成并准备上架的 iOS 应用程序来说&#xff0c;通过苹果公司的审核是非常重要的一步。苹果公司会对应用程序进行严格的检查&#xff0c;以确保应用程序的质量和安全性。本文将介绍 iOS 应用程序审核的流程和时间&#xff0c;希望能够帮助开发者更好地了解和…

基于C#制作一个连连看小游戏

基于C#制作一个连连看小游戏,实现:难易度选择、关卡选择、倒计时进度条、得分计算、音效播放等功能。 目录 引言游戏规则开发环境准备游戏界面设计游戏逻辑实现图片加载与显示鼠标事件处理游戏优化与扩展添加关卡与难度选择说明</

【Python笔记-设计模式】单例模式

一、说明 单例是一种创建型设计模式&#xff0c;能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。 (一) 解决问题 维护共享资源&#xff08;数据库或文件&#xff09;的访问权限&#xff0c;避免多个实例覆盖同一变量&#xff0c;引发程序崩溃。 …

Flutter开发1:学习大纲

引言 欢迎来到Flutter开发系列的第一篇博客&#xff01;在这个系列中&#xff0c;我们将一起探索Flutter的奇妙世界。如果你是一个热爱移动应用开发的开发者&#xff0c;或者对跨平台开发有兴趣&#xff0c;那么Flutter绝对值得你学习和尝试。 为什么选择Flutter&#xff1f;…