Leetcode 209: 长度最小的子数组问题

Time: 2019-08-01

题目描述

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

示例:

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路1

最直白的解法可以帮助理解题意,用循环来解这个问题,直接枚举然后判定。

代码1

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        min_len = 1e31
        _sum = 0
        for i in range(len(nums)):
            for j in range(i, len(nums)):
                _sum = 0
                for k in range(i, j + 1):
                    _sum += nums[k]
                if _sum >= s and j - i + 1 < min_len:
                    min_len = j - i + 1 
        if min_len == 1e31:
            return 0
        else:
            return min_len  

时间复杂度:
空间复杂度:

思路2:前缀和

前缀和复习:给定一个数组

前缀和:

按照这个定义,[i,j]下标之间的元素和为

代码2

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        min_len = 1e31
        # 求解presum数组
        presums = [0]
        temp = 0
        for i in range(len(nums)):
            temp += nums[i]
            presums.append(temp)
        # print(presums)
            
        for i in range(1, len(nums) + 1):
            for j in range(i, len(nums) + 1):
                _sum = presums[j] - presums[i-1] 
                if _sum >= s and j - i + 1 < min_len:
                    min_len = j - i + 1
        if min_len == 1e31:
            return 0
        else:
            return min_len

用前缀和数组简化了最内层循环计算[i,j]之间元素和。

相当于以空间换了一定的时间。

时间复杂度:
空间复杂度:

思路3

本题看题目意思,是有时间复杂度的解法。

这种时间复杂度的算法一定是在理解并发现了题目的一些性质的基础上才能完成的。

固定右边下标j。那么从j往左,会是这样一种情况:

√√√√√√×××××××j

√表示从这个下标加到j满足条件。

这是性质1。还有个更重要的性质是:j+1对应的满足的下标i要么是在j对应的i基础上不动,要么是继续往右。

这是性质2。

由此可以写出更优的算法,看看能不能AC,前面两种算法都是超时的。

j是很稳定的向右走,用for循环,i是不稳定的,用while循环

其中,j下标是主指针,i下标是辅指针。

如何跟踪i到j之间的和呢?
一种方式是用前缀和,另一种方式是用变量跟踪,j往后一位就 += nums[j],i往后一位就 -= nums[i].

这就是同向双指针的问题。

代码3--AC,但是效率并不高

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        min_len = 1e31
        _sum = 0

        # 求解presum数组,这里的presums数组长度比原来数组多一个元素,方便处理,下标需要+1算起
        presums = [0]
        temp = 0
        for i in range(len(nums)):
            temp += nums[i]
            presums.append(temp)
        print(presums)
        
        i = 0
        
        for j in range(len(nums)):
            # print("j: ", i, j)
            while i <= j:
                # 计算i到j之间的和
                _sum = presums[j + 1] - presums[i]
                print("i, j, sum: ", i, j, _sum)
                if _sum < s:
                    print("i and j: ", i, j)
                    break

                else:
                    if j + 1 - i < min_len:
                        min_len = j + 1 - i
                    i += 1
        if min_len == 1e31:
            return 0
        else:
            return min_len

时间复杂度:
空间复杂度:

更进一步的代码需要再思考这个问题。
这里,如何得出时间复杂度为还不是特别确定。

你可能感兴趣的:(Leetcode 209: 长度最小的子数组问题)