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) 时间复杂度的解法。


下面是滑动窗口法:每次加一个新数进来,如果和大于s,那么计算区间长度,每一取一个最小的区间长度。
如果和大于s,那么就需要缩小左边界,并且判断缩小之后 的总和是否满足大于等于s。
每次不满足总和大于等于s,我们就要右移right, 加入一个新的数进来。

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        n = len(nums)
        length = float('inf')
        left, right = 0, 0
        ans = 0
        while right < n:
            ans += nums[right]
            while ans >= s:
                if right + 1 - left < length:
                    length = min(right + 1 - left, length)
                ans -= nums[left]
                left += 1
            right += 1

        return length if length != float('inf')  else 0

下面是powcai大佬的二分法:
num[i]的值是前i个数的总和, nums[j] - nums[i]就是( j , i ]的总和,所以我们可以使用二分进行区间缩小。
区间的上界就是所有数的总和,下界就是s。

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums : return 0
        # 求前缀和
        for i in range(1, len(nums)):
            nums[i] += nums[i - 1]
        #print(nums)
        # 总和都小于 s 时候
        if nums[-1] < s: return 0
        res = float("inf")
        nums = [0] + nums
        for i in range(1, len(nums)):
            if nums[i] - s >= 0:
                # 二分查找
                loc = bisect.bisect_left(nums, nums[i] - s)
                if nums[i] - nums[loc] >= s:
                    res = min(res, i - loc)
                    continue
                if loc > 0:
                    res = min(res, i - loc + 1)
        return res 

作者:powcai
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum/solution/hua-dong-chuang-kou-on-er-fen-fa-onlogn-by-powcai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

官方题解:

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if not nums:
            return 0
        
        n = len(nums)
        ans = n + 1
        sums = [0]
        for i in range(n):
            sums.append(sums[-1] + nums[i])
        
        for i in range(1, n + 1):
            target = s + sums[i - 1]
            bound = bisect.bisect_left(sums, target)
            if bound != len(sums):
                ans = min(ans, bound - (i - 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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(#,二分查找,#,数组,二分法,算法,leetcode)