題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/minimum-size-subarray-sumpython
給定一個含有 n 個正整數的數組和一個正整數 s ,找出該數組中知足其和 ≥ s 的長度最小的連續子數組,並返回其長度。若是不存在符合條件的連續子數組,返回 0。數組
示例:bash
輸入: s = 7, nums = [2,3,1,2,4,3] 輸出: 2 解釋: 子數組 [4,3] 是該條件下的長度最小的連續子數組。
進階:微信
若是你已經完成了O(n) 時間複雜度的解法, 請嘗試 O(n log n) 時間複雜度的解法。app
思路:雙指針 / 前綴和+二分查找spa
先看題目,題目說明,數組 nums 給定的元素都是正整數,同時給一個整數 s,求子數組和大於等於 s 的最小連續子數組,返回長度。不存在則返回 0。3d
這裏先說下特殊狀況,上面根據題意已說明,nums 中的元素都是正整數,那麼若是數組全部元素和都小於 s 的話,那麼子數組是必定不能知足要求的,直接返回 0 便可。指針
進階 提示的內容部分中,要求先完成 O(n) 時間複雜度的解法。這就是咱們如今要說明的 雙指針 思路的解法。code
具體的實現思路:blog
left
,right
,同時指向索引爲 0 的初始位置;num_sum
存儲數組和,用以與 s
比較;num_sum
值,當 num_sum
知足大於等於 s
的條件時,先記錄此時的數組長度,而後嘗試縮小數組的長度。num_sum
和 s
的值。循環直至指針到達末尾位置。雙指針實現思路的過程,可見下圖:
關於圖中的參數
當 num_sum 大於等於 s 時表示知足條件。
s:題目所給的目標值
num_sum:子數組之和
left:左指針
right:右指針
ans:知足條件的子數組長度
具體的代碼見 【代碼實現 # 雙指針】。
上面是雙指針的思路,下面嘗試使用 O(nlogn) 複雜度的方法:前綴和 + 二分查找。
關於前綴和,這裏就不展開說明這個概念了。這裏咱們用數組 num_sum
存儲 nums
的前綴和。
num_sum[i]
:表示 nums[0]
到 nums[i-1]
的元素之和。
仍是由於有 【給定一個含有 n 個正整數的數組】 的前提,那麼咱們存儲前綴和的數組必定是遞增升序的,這樣也能保證二分查找的正確性。
當咱們獲得存儲前綴和的數組以後,咱們能夠遍歷數組經過二分查找獲得一個索引 index
,使得 num_sum[index] - num_sum[i-1] >= s
,更新維護子數組的長度,(此時的長度爲 index -(i-1))
具體的代碼見 【代碼實現 # 前綴和+二分查找】。
# 雙指針 class Solution: def minSubArrayLen(self, s: int, nums: List[int]) -> int: # 先處理特殊狀況,由於給定的數組都是正整數 # 若是數組中全部元素的和都小於 s # 那麼子數組的和必定都小於 s,直接返回 0 if sum(nums) < s: return 0 # 定義雙指針 left = 0 right = 0 length = len(nums) # 定義變量,存儲元素和,用以跟 s 比較 num_sum = 0 ans = float('inf') # 遍歷數組,移動指針 while right < length: num_sum += nums[right] # 知足條件時,嘗試縮小子串的長度,尋找最小的連續子數組 while num_sum >= s: ans = min(ans, right - left + 1) num_sum -= nums[left] left += 1 right += 1 return ans # 前綴和+二分查找 class Solution: def minSubArrayLen(self, s: int, nums: List[int]) -> int: def bin_search(num_sum, left, right, target): while left < right: mid = (left + right) // 2 if num_sum[mid] < target: left = mid+1 else: right = mid # 這裏要注意,有可能最後一位元素大於目標值 # 這種狀況要考慮,若是不知足,也就是最後一位元素不大於目標值時,返回 -1,這種狀況不更新計算長度。 return left if num_sum[left] >= target else -1 # 先處理特殊狀況,當數組中的元素和小於 s, # 則表示數組中全部子數組的和都不可能大於 s # 這個時候,直接返回 0 if sum(nums) < s: return 0 ans = float('inf') length = len(nums) # 存儲前綴和 num_sum = [0] for i in range(length): num_sum.append(num_sum[-1] + nums[i]) # 經過二分查找,找到符合條件的索引,計算長度 for i in range(1, length+1): target = s + num_sum[i-1] index = bin_search(num_sum, 1, length, target) if index != -1: ans = min(ans, index-(i-1)) return ans
雙指針 | 實現結果
前綴和+二分查找 | 實現結果
題目中要求先實現 O(n) 時間複雜度的解法。這裏使用雙指針的方法,具體實現以下:
left, right
,定義變量 num_sum
存儲子數組的和。num_sum
小於目標值 s
時,先移動右指針,維護更新 num_sum
。當 num_sum
知足條件也就是大於或等於 s
時,先記錄此時子數組的長度。此時移動左指針嘗試縮小數組,再次比較 num_sum
和 s
的值。循環判斷直至 right
到達末尾位置。題目進階說能夠嘗試 O(nlogn) 時間複雜度的解法,這裏可聯想到二分查找。一樣根據第一項所說的前提,能夠定義數組存儲 nums
數組的元素前綴和。具體實現以下:
num_sum
存儲數組的前綴和,num_sum[i]
表示 nums[0]
到 nums[i-1]
元素之和。index
使得 num_sum[index]-nums[i-1]
的和大於或等於 s
,記錄此時的子數組長度(index-(i-1))。文章原創,若是以爲寫得好,歡迎關注點贊。微信公衆號《書所集錄》同步更新,一樣歡迎關注點贊。