天天看點

100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組

作者:碼科智能
在這個系列的部落格中,我們根據LeetCode官方給出的每個題目的出現頻率,整理并收錄了每個類别裡高頻出現的題目,從簡單到中等再到困難,為你提供解題技巧和最佳實踐。我們将介紹常見的算法思想,如貪心算法、動态規劃、回溯算法等,希望能幫助你提高算法水準,成為你進入人工智能行業敲門磚。
100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組

209. 長度最小的子數組(難度3/頻率4)

給定一個含有 n 個正整數的數組和一個正整數 s ,找出該數組中滿足其和 ≥ s 的長度最小的 連續子數組,并傳回其長度。如果不存在符合條件的子數組,傳回 0。

示例 1:

輸入:target = 7, nums = [2,3,1,2,4,3]

輸出:2解釋:子數組 [4,3] 是該條件下的長度最小的子數組。

示例 2:

輸入:target = 4, nums = [1,4,4] 輸出:1

解題思路

做深度學習視覺的同學應該對操作數組很熟悉,數組操作中一個重要的方法:滑動視窗。

所謂滑動視窗,就是不斷的調節子序列的起始位置和終止位置,進而得出我們要想的結果。

在暴力解法中,都是每次确定子數組的開始下标,然後通過兩個for循環得到長度最小的子數組,是以時間複雜度較高。

那麼滑動視窗如何用一個for循環來完成這個操作呢。首先要思考如果用一個for循環,那麼應該表示滑動視窗的起始位置,還是終止位置。如果隻用一個for循環來表示滑動視窗的起始位置,那麼如何周遊剩下的終止位置?此時難免再次陷入暴力解法的怪圈。

是以隻用一個for循環,那麼這個循環的索引,一定是表示滑動視窗的終止位置(想到這點非常重要)。

那麼問題來了, 滑動視窗的起始位置如何移動呢?以題目中的示例來舉例,s=7

100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組
100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組
100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組

在本題中實作滑動視窗,主要确定如下三點:

  • 視窗内是什麼?
  • 如何移動視窗的起始位置?
  • 如何移動視窗的結束位置?

視窗就是 滿足其和 ≥ s 的長度最小的 連續 子數組。

視窗的起始位置如何移動:如果目前視窗的值大于s了,視窗就要向前移動了(也就是該縮小了)。

視窗的結束位置如何移動:視窗的結束位置就是周遊數組的指針,也就是for循環裡的索引。

解題的關鍵在于視窗的起始位置如何移動,如圖所示:

100道高頻LeetCode算法圖文題解,滑動視窗之最小長度子數組

可以發現滑動視窗的精妙之處在于根據目前子序列和大小的情況,不斷調節子序列的起始位置。進而将O(n^2)暴力解法降為O(n)。

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        res = float("inf")  # 定義一個無限大的數
        sum, index = 0, 0
        for i in range(len(nums)):
            sum += nums[i]
            while sum >= s:
                res = min(res, i-index+1)  # 最小的索引
                sum -= nums[index] # 移動起始位置
                index += 1
        return 0 if res==float("inf") else res           

題目總結

本題其實有一個重點,就是真正了解滑動視窗,怎麼定義滑動視窗兩個指針的移動,這道題可以給數組操作帶來進一步的了解。

繼續閱讀