題目描述
給定一個含有 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
結題思路
思路一:暴力遍歷:(Python超時)
初始化子數組的最小長度爲無窮大,枚舉數組 nums 中的每個下標作爲子數組的開始下標,對於每個開始下標 i,需要找到大於或等於 i 的最小下標 j,使得從 nums[i] 到 nums[j] 的元素和大於或等於 s,並更新子數組的最小長度(此時子數組的長度是 j-i+1)。
- 複雜度分析
- 時間複雜度:,爲數組長度。
- 空間複雜度:
思路二:二分查找+前綴和
暴力法中再確定每個子數組的開始下標後,找到長度最小的子數組需要的時間。如果使用二分查找,可以將時間複雜度降到。
使用二分查找要額外創建一個數組用來存儲數組的前綴和,其中表示從到的元素和。得到前綴和之後對於每個開始下標i,可以通過二分查找得到>=i的最小下標,使得,並更新子數組的最小長度。
因爲題目中的數組元素均爲正數,所以前綴和一定是遞增的,這是使用二分查找的正確性的前提。Python
中bisect.bisect_left
實現了二分查找大於等於某個數的第一個位置的功能。
- 複雜度分析
- 時間複雜度:,爲數組長度。
- 空間複雜度:,額外創建數組sums存儲前綴和。
思路三:雙指針
前兩種方法都是每次確定子數組的開始下標後得到長度最小的子數組,爲了降低時間複雜度可以使用雙指針。
定義指針 和 分別表示子數組的開始位置和階數位置,維護變量 存儲子數組中的元素和。
開始時 和 都指向下標0,。
每一輪迭代都將 加到 中,如果 ,更新子數組的最小常數,然後從 中減掉 ,並把 右移,直到 ,此過程中要更新子數組最小長度。每輪迭代後將 後移。
- 複雜度分析
- 時間複雜度:,其中是數組的長度。指針 和 最多各移動 次。
- 空間複雜度:。
代碼實現
思路二:二分查找+前綴和
class Solution:
def minSubArrayLen(self, s, nums):
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/
思路三:雙指針
class Solution(object):
def minSubArrayLen(self, s, nums):
n = len(nums)
start, end = 0,0
mysum = 0
ans = n+1
while end < n:
mysum += nums[end]
while mysum >= s:
ans = min(ans, end-start+1)
mysum -= nums[start]
start += 1
end += 1
return 0 if ans == n+1 else ans
Tips
- 涉及連續子數組的問題通常有兩種思路:一是
滑動窗口
、二是前綴和
。 Python
中bisect.bisect_left
實現了二分查找大於等於某個數的第一個位置的功能。