方法 1:暴力
想法按照題目要求直接求。把所有可能的子陣列求和並更新 \textans ,直到我們找到最優子陣列且和滿足 \text \geq \textsum≥s 。
演算法初始化 \text=\textans=int_max
用變數 ii 從左到右遍歷陣列:
用變數 jj 從當前元素到陣列尾部遍歷:
將 ii 到 jj 這些元素求和得到 \textsum
如果和 \textsum 比 ss 大:
更新 \text = \min(\text, (j - i + 1))ans=min(ans,(j−i+1))
繼續迭代
c++int minsubarraylen(int s, vector& nums)
if (sum >= s) }}
return (ans != int_max) ? ans : 0;
}複雜度分析
時間複雜度:o(n^3)o(n
3) 。
對陣列裡的每乙個元素,我們從它開始列舉所有的子陣列,需要的時間為 o(n^2)o(n 2)。
將每乙個子陣列求和的時間複雜度為:o(n)o(n) 。
所以總時間複雜度為:o(n^2 * n) = o(n^3)o(n
2∗n)=o(n
3) 。
空間複雜度:o(1)o(1)。只是用了常數個額外變數。
方法 2:優化的暴力
想法在方法 1 中,我們注意到求子陣列的和需要的時間為 o(n)o(n) 。我們其實可以很容易地實現 o(1)o(1) 時間的求和,只需要從開始元素用乙個累加器儲存和。我們將累積和儲存在 \textsums 中,通過這種方法,我們可以輕鬆求出任意子區間的和。
演算法演算法流程與方法 1 類似。
唯一的不同是求子陣列的和:
建立乙個大小為 \textnums 的向量 \textsums
初始化 \text[0]=\text[0]sums[0]=nums[0]
遍歷 向量 \textsums :
更新 \text[i] = \text[i-1] + \text[i]sums[i]=sums[i−1]+nums[i]
從 ii 到 jj 的和計算方法:
\text=\text[j] - \text[i] +\text[i]sum=sums[j]−sums[i]+nums[i] ,其中 \text[j] - \text[i]sums[j]−sums[i] 是從第 i+1i+1 個元素到第 jj 個元素的和。
c++int minsubarraylen(int s, vector& nums)}}
return (ans != int_max) ? ans : 0;
}複雜度分析
時間複雜度:o(n^2)o(n
2) 。
找到所有子陣列的時間複雜度為 o(n^2)o(n
2) 。
計算子陣列的和為 o(1)o(1) 的時間。
因此,總時間複雜度為:o(n^2 * 1) = o(n^2)o(n
2∗1)=o(n
2) 。
空間複雜度:o(n)o(n) 。
額外的 \textsums 陣列空間大小為 o(n)o(n) 。
方法 3:使用二分查詢
想法我們可以用二分查詢的方法優化方法 2 。我們找到從下標 ii 開始滿足 \text \geq \textsum≥s 的子陣列需要 o(n)o(n) 的時間。但是我們可以用二分查詢的方法把這個時間優化到 o(\log(n))o(log(n)) 。在方法 2 中,我們從 ii 開始找 jj ,直到找到 \text=\text[j] - \text[i] + \text[i]sum=sums[j]−sums[i]+nums[i] 大於等於\texts 的。與其線性地查詢這個和,我們可以使用二分搜尋的方法找到 \textsums 中不小於 \text+\text-\texts+sums[i]−nums[i] 的第乙個 \textsums[j] ,可以用 c++ stl 中的 \text 函式做到。
演算法建立大小為 n+1n+1 的陣列 sumssums :
\text[0]=0\text\text[i]=\text[i-1]+\text[i-1]
sums[0]=0, sums[i]=sums[i−1]+nums[i−1]
從 i=1i=1 到 nn 列舉:
在 \textsums 中找到值 \textto_find ,滿足從 ii 開始到這個位置的和大於等於 ss 且是最小子陣列:
\text=\text+\text[i-1]
to_find=s+sums[i−1]
+在 \textsums 中找到值滿足大於等於 \text 的下標,記作 \textbound
+如果我們在 \textsums 中找到了值 \text, 那麼:
- 當前子陣列的大小為:
\text - (\text()+i-1)bound−(sums.begin()+i−1)
- 將 ansans 與當前陣列的大小做比較,並把較小值儲存到 ansans 中
c++int minsubarraylen(int s, vector& nums)
}return (ans != int_max) ? ans : 0;
}複雜度分析
時間複雜度:o(n\log(n))o(nlog(n)) 。
對向量中的每乙個元素,從它開始用二分查詢找到子陣列,滿足和大於 ss 。因此,遍歷的時間複雜度是 o(n)o(n) ,二分查詢的時間複雜度是 o(\log(n))o(log(n)) 。
因此,總時間複雜度是 o(n*\log(n))o(n∗log(n))
空間複雜度:o(n)o(n)。\textsums 需要額外的 o(n)o(n) 空間。
方法 4:使用兩個指標
想法到現在為止,我們都保持子陣列的左端點不動去找右端點。其實一旦知道這個位置開始的子陣列不會是最優答案了,我們就可以移動左端點。我們用 2 個指標,乙個指向陣列開始的位置,乙個指向陣列最後的位置,並維護區間內的和 \textsum 大於等於 ss 同時陣列長度最小。
演算法初始化 \textleft 指向 0 且初始化 \textsum 為 0
遍歷 \textnums 陣列:
將 \text[i]nums[i] 新增到 \textsum
當 \textsum 大於等於 ss 時:
更新 \text=\min(\text,i+1-\text)ans=min(ans,i+1−left) ,其中 i+1-\texti+1−left是當前子陣列的長度
然後我們可以移動左端點,因為以它為開頭的滿足 \text \geq ssum≥s 條件的最短子陣列已經求出來了
將 \textsum 減去 \textnums[left] 然後增加 \textleft
c++int minsubarraylen(int s, vector& nums)
}return (ans != int_max) ? ans : 0;
}複雜度分析
時間複雜度:o(n)o(n) 。每個指標移動都需要 o(n)o(n) 的時間。
每個元素至多被訪問兩次,一次被右端點訪問,一次被左端點訪問。
空間複雜度: o(1)o(1) 。\textleft,\textsum,\textans 以及 ii 這些變數只需要常數個空間。
長度最小的子陣列
給定乙個含有n個正整數的陣列和乙個正整數s 找出該陣列中滿足其和 s的長度最小的連續子陣列。如果不存在符合條件的連續子陣列,返回 0。示例 輸入 s 7,nums 2,3,1,2,4,3 輸出 2解釋 子陣列 4,3 是該條件下的長度最小的連續子陣列。高階 如果你已經完成了o n 時間複雜度的解法,...
長度最小的子陣列
問題 給定乙個含有 n 個正整數的陣列和乙個正整數 s 找出該陣列中滿足其和 s 的長度最小的連續子陣列。如果不存在符合條件的連續子陣列,返回 0。示例 輸入 s 7,nums 2,3,1,2,4,3 輸出 2 解釋 子陣列 4,3 是該條件下的長度最小的連續子陣列。分析 暴力法 求出每個子陣列的和...
長度最小的子陣列
給定乙個含n個正整數的陣列和乙個正整數s,找出該陣列中滿足其和 s的長度最小的連續子陣列,並返回其長度,如果不存在符合條件的連續子陣列,就返回0。思路 這題也是乙個關於滑動視窗的題。這題是找出其中滿足大於等於的長度,與只等於的解法稍有不同。因為全是正整數,因此我們在向後移動的過程中,sum是乙隻增大...