代码随想录刷题-数组-长度最小的子数组

长度最小的子数组

本节对应代码随想录中:代码随想录,讲解视频:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili

习题

题目链接:209. 长度最小的子数组 - 力扣(LeetCode)

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

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

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

暴力解法

直接能想到的就是用两个 for 循环,第一个循环遍历起始位置,第二个 for 循环向后遍历直到找到满足其和 ≥ target 的位置,我的代码如下(非最优,并且会超时,仅用于个人分析记录):

class Solution {
   public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int res = 999999;
        for (int i = 0; i < nums.size(); i++) {
            int sum = 0, count = 999999;
            for (int j = i; j < nums.size(); j++) {
                sum += nums[j];
                if (sum >= target) {
                    count = j - i + 1;
                    break;
                }
            }
            if (count < res) {
                res = count;
            }
        }
        if(res!=999999){
            return res;
        }
        return 0;
    }
};
  • 时间复杂度:O(n^2)。这段代码使用了两层嵌套循环。外层循环遍历整个数组,内层循环计算从当前元素开始的子数组的和,直到和大于等于 target 为止。因此,总的时间复杂度为 O(n^2)。
  • 空间复杂度:O(1)。这段代码只使用了常数级别的额外空间,即定义了几个整型变量,因此空间复杂度为 O(1)。

比较代码随想录上的暴力解法,有以下几点可以注意下

  • 初始 res 时本意是想初始一个比较大的值,用 res=INT32_MAX 更好
    • INT_MAX 一般和 INT32_MAX 相同,但如果是16位时, INT_MAX 要更小点,所以用 INT32_MAX 更好
  • 代码中后面两个 if 判断换成三元运算符更好,即 ` ? :

滑动窗口

C++中的滑动窗口是一种常见的数组/字符串问题的解决方案,它可以将一个问题的时间复杂度从 O(n^2)降低到 O(n)或者 O(nlogn),通常涉及到从给定的数据序列中找到需要进行操作的子串或子序列等。

滑动窗口的基本思路是:用两个指针表示现在关注的区间,即左端点(left pointer)和右端点(right pointer),让其构成一个窗口。移动右指针扩大长度,直到包含满足条件的子串(比如大于等于target)。然后,尝试缩小左端点以尽可能的减小满足条件的窗口长度,同时继续移动右指针,查找再次满足条件的子串。重复这个过程直到最右侧,得到最优解。

暴力解法中我们是遍历窗口的初始位置,对于每个初始位置向后遍历剩余元素寻找满足条件的窗口。而滑动窗口是遍历窗口的结束位置,如果当前窗口满足条件,那左边的指针就要向右移动即缩小窗口,其实也算是双指针。

class Solution {
   public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left = 0, sum = 0,subLength = 0;
        int ans = INT32_MAX;  // 答案初始化为整数最大值

        for (int right = 0; right < nums.size(); right++) {
            sum += nums[right];

            while (sum >= target) {  // 当sum>=target时,意味着当前窗口的总值大于等于target了
                subLength = (right - left + 1);  // 取子序列的长度
                ans = ans < subLength ? ans : subLength;  // 更新ans
                sum -= nums[left]; // 窗口右移那就要减去原来窗口左边的值
                left++;  // 通过左指针向右移动收缩窗口
            }
        }

        return ans == INT32_MAX ? 0 : ans;  // 如果没找到就返回0
    }
};
  • 时间复杂度:O(n)。:这段代码使用了滑动窗口的算法。其中,left 和 right 指针分别指向当前窗口的左右两端,sum 表示当前窗口中所有元素的和。在遍历过程中,因为 left 和 right 指针都只会向右移动,所以总的时间复杂度为 O(n)。
  • 空间复杂度:O(1)。这段代码只使用了常数级别的额外空间,即定义了几个整型变量,因此空间复杂度为 O(1)。

代码中 while (sum >= target) 使用的是 while 而不是 if,因为当缩小窗口的时候是一个循环的过程。

如1 1 1 4中 target=4,那找到满足条件的窗口=4的时候,左指针应该是从初始的1不断向右移动直到新的窗口不大于等于 target 时停止

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值