[LeetCode 解題紀錄] 209. Minimum Size Subarray Sum
209. Minimum Size Subarray Sum
[LeetCode 解題紀錄] 209. Minimum Size Subarray Sum

209. Minimum Size Subarray Sum
https://leetcode.com/problems/minimum-size-subarray-sum/description/
Problem:
Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead.
Example 1:
Input: target = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: The subarray [4,3] has the minimal length under the problem constraint.
Example 2:
Input: target = 4, nums = [1,4,4]
Output: 1
Example 3:
Input: target = 11, nums = [1,1,1,1,1,1,1,1]
Output: 0
Constraints:
1 <= target <= 1091 <= nums.length <= 1051 <= nums[i] <= 104
Follow up: If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log(n)).
題意
給定一個含有 n 個正整數的陣列 nums 和一個正整數 target。 請找出該陣列中滿足元素總和大於等於 target 的「長度最小」的連續子陣列,並返回其長度。如果不存在符合條件的子陣列,請返回 0。
問題解析
首先,看到題目我們可以先挑出關鍵字:重點:
- 正整數
- 「長度最小」的「連續」子陣列
- 最後要 return 長度
也就是要把子陣列加總後,找出最短且符合總和大於等於 target 的情況。
解法
暴力法 -> Sliding Window
先從暴力法思考,最直覺就是加總所有可能性的子陣列,從這個方向出發,可以發現如果加總全部可能的話,其實中間有許多操作是重複做好幾次的。
如果我們是一個可變動的視窗,發現加總不夠 target 的時候,就往右補一個進來,發現超過 target 的時候,除了紀錄當下的視窗長度外,同時也不斷的縮小,直到符合條件,再繼續往右補。
- 定義狀態:一個變數 currentSum 來記錄當前視窗內的數字總和。
- right:外層迴圈往右擴張,每次都把 nums[right] 加進 currentSum 裡。
- left:當 currentSum >= target 時,代表條件滿足,這時候進入 while 迴圈來吐出先前的值。
function minSubArrayLen(target: number, nums: number[]): number {
const len = nums.length;
let minLength = Infinity;
// base case
if (len === 0) return 0;
let left = 0;
let currentSum = 0;
// 1. 外層迴圈往右擴張
for (let right = 0; right < len; right++) {
currentSum += nums[right];
// 2. 當 currentSum >= target 時,代表條件滿足
// 只要大於等於,就立刻進入 while 準備記錄並收縮
while (currentSum >= target) {
// 檢查更新最短長度
minLength = Math.min(minLength, right - left + 1);
// 記錄完之後,才把左邊的元素吐出來,試圖尋找更短的可能
currentSum -= nums[left];
left++;
}
}
// 最後檢查:如果 minLength 還是 Infinity,代表從頭到尾都沒找到合法的
return minLength === Infinity ? 0 : minLength;
};
讓我們先來 Dry run 一次
/*
target = 7, nums = [2, 3, 1, 2, 4, 3]
*/
// --- 開始向右擴張 ---
minLength=Infinity
[2, 3, 1, 2, 4, 3]
l
r
currentSum=2 (小於 7,繼續擴張)
minLength=Infinity
[2, 3, 1, 2, 4, 3]
l
r
currentSum=5 (小於 7,繼續擴張)
minLength=Infinity
[2, 3, 1, 2, 4, 3]
l
r
currentSum=6 (小於 7,繼續擴張)
// --- 第一次觸發收縮條件 ---
minLength=Infinity
[2, 3, 1, 2, 4, 3]
l
r
currentSum=8 (大於等於 7,觸發 while 迴圈)
// 【記錄】更新 minLength = min(Infinity, 4) = 4
// 【吐出】減去 nums[l] 的 2,l 往前
minLength=4
[2, 3, 1, 2, 4, 3]
l
r
currentSum=6 (小於 7,跳出 while,r 繼續擴張)
// --- 再次擴張並觸發收縮 ---
minLength=4
[2, 3, 1, 2, 4, 3]
l
r
currentSum=10 (大於等於 7,觸發 while 迴圈)
// 【記錄】更新 minLength = min(4, 4) = 4
// 【吐出】減去 nums[l] 的 3,l 往前
minLength=4
[2, 3, 1, 2, 4, 3]
l
r
currentSum=7 (大於等於 7,繼續在 while 迴圈內)
// 【記錄】更新 minLength = min(4, 3) = 3
// 【吐出】減去 nums[l] 的 1,l 往前
minLength=3
[2, 3, 1, 2, 4, 3]
l
r
currentSum=6 (小於 7,跳出 while,r 繼續擴張)
// --- 最後一次擴張與連續收縮 ---
minLength=3
[2, 3, 1, 2, 4, 3]
l
r
currentSum=9 (大於等於 7,觸發 while 迴圈)
// 【記錄】更新 minLength = min(3, 3) = 3
// 【吐出】減去 nums[l] 的 2,l 往前
minLength=3
[2, 3, 1, 2, 4, 3]
l
r
currentSum=7 (大於等於 7,繼續在 while 迴圈內)
// 【記錄】更新 minLength = min(3, 2) = 2 <-- 找到最佳解
// 【吐出】減去 nums[l] 的 4,l 往前
minLength=2
[2, 3, 1, 2, 4, 3]
l
r
currentSum=3 (小於 7,跳出 while)
// r 走到底,迴圈結束。
// 最終回傳 minLength = 2
時間複雜度:O(N)
- 雖然我們是兩層迴圈,但我們要看的是指標移動的總次數,外層的
right指標從陣列最左邊走到最右邊,總共走了 N 步。 內層的left指標雖然在while裡面,但它只會前進,不會後退,所以它最多也是從最左邊走到最右邊,總共最多走 N 步,也就是說陣列中的每一個數字,最多只會被right吃進去 1 次,並且最多被left吐出來 1 次。 總操作次數大約是 2N,忽略常數後,時間複雜度就是 O(N)
空間複雜度:O(1)
更多演算法與資料結構文章:
[embed]

메타데이터
- post_id
- 6a2e3dcedf0b
- slug
- leetcode-解題紀錄-209-minimum-size-subarray-sum-6a2e3dcedf0b
- url
- https://medium.com/%E6%8A%80%E8%A1%93%E7%AD%86%E8%A8%98/leetcode-%E8%A7%A3%E9%A1%8C%E7%B4%80%E9%8C%84-209-minimum-size-subarray-sum-6a2e3dcedf0b
- canonical_url
- https://medium.com/%E6%8A%80%E8%A1%93%E7%AD%86%E8%A8%98/leetcode-%E8%A7%A3%E9%A1%8C%E7%B4%80%E9%8C%84-209-minimum-size-subarray-sum-6a2e3dcedf0b
- author_url
- https://medium.com/@sean1093
- status
- ok
- fetched_at
- 2026-07-09 13:13:48