【小白用python刷Leetcode】209. 长度最小的子数组

209. 长度最小的子数组

题目描述

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。

示例:

输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2

解释:子数组 [4,3] 是该条件下的长度最小的连续子数组。

进阶:如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

我的思路(小白思路)

第一反应是利用滑窗解决(可能也叫快慢指针?),感觉一般讲起连续子数组,要么是滑窗,要么就是动态规划。这道题我自己做就是限定滑窗的边界i,j来确定子数组。具体思路就是如果滑窗内数组之和tmp为s,为了以防之后还有更短的数组,右边界向后滑1(j+1);如果滑窗内数组之和tmp小于s,则需要增大数组之和tmp,也是右边界向后滑1(j+1);如果滑窗内数组之和tmp大于s,则需要减小数组之和tmp,左边界向后滑1(i+1)。

除此之外还需要两个额外的变量:一个记录子数组最小长度l,先预设正无穷;另一个表示当前数组是否存在满足条件的子数组exist,相当于是个Flag,如果存在为1,不存在为0,最后根据exist来决定是不是输出0。感觉加Flag的思路并不是特别简洁,应该从循环的结果上就能判断是不是存在满足条件的子数组,但是一时没有理清楚,暂且先这样。

这种思路虽然说空间复杂度O(1)还好,但是时间复杂度较高为O(n)(似乎也还行?)。

def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = float('inf')
        i = 0
        j = 1
        exist = 0
        while j <= len(nums):
            if i >= j:  #为了防止边界颠倒的情况
                j = i+1
            else:
                tmp = sum(nums[i:j])
                if tmp == s:                
                    if len(nums[i:j]) < l:
                        l = len(nums[i:j])
                        exist = 1
                    j+=1
                elif tmp < s:
                    j+=1
                else:
                    if len(nums[i:j]) < l:
                        l = len(nums[i:j])
                        exist = 1
                    i+=1
        if exist == 0:
            return 0
        else:
            return l

官方思路

思路一:双指针(实锤叫双指针没错了)

这个思路和我的小白思路很像,但是是改进版。说实话能在官方题解里看到和自己相像的思路还是很惊喜的,谁让我是小白呢。具体来说就是每次算sum的时候,不需要全部重新计算,快指针后移一下,则在原先sum的基础上加,慢指针后移则减,其他部分都是比较相似的。还有个小的点就是其实l设n+1就可以了,没必要设正无穷。这样还能省去exist这个Flag,因为只要最后l仍等于n+1,则表明没有符合要求的子数组,输出0。

代码的话就直接抄leetcode官方题解了,写得很简洁,看起来赏心悦目啊,尤其是循环内的设计,那个双while的嵌套,感觉真的是我这种一般只会用if else的小白无法企及的高度啊,很精妙。也试着在自己原来的基础上改,但是反而跑不通了,改了很久都没AC,遂放弃,谁让我是小白呢。。。

def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums:
            return 0
        
        n = len(nums)
        ans = n + 1
        start, end = 0, 0
        total = 0
        while end < n:
            total += nums[end]
            while total >= s:
                ans = min(ans, end - start + 1)
                total -= nums[start]
                start += 1
            end += 1
        
        return 0 if ans == n + 1 else ans

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum/solution/chang-du-zui-xiao-de-zi-shu-zu-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路二:折半

其实如果要求时间复杂度O(n log n)的话,一般都会想到二分啊折半啊这类的吧。但是觉得明明都已经O(n),干嘛还要O(n log n),反向操作?没办法啊,小白啊,理解不上去啊。所以就是草草想了一下,也没深究。看到官方题解果然也是折半,小安慰一下。由于也没仔细想,所以这里就不详细说了,反正没有上面方法好就是了!哈哈,小白就是这么不求甚解。待我研究透之后再来补上,嗯,一定会的!

以上就是我,一个正儿八经的小白(大神们通过看代码应该也感觉出来了),对这道题的理解,欢迎诸位指正讨论,感谢阅读。

原题链接:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值