長度最小的子陣列

2021-08-16 07:14:18 字數 3561 閱讀 7919

方法 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是乙隻增大...