引入:滑動窗口
首先,這是滑動窗口的第一道題,所以簡短的說一下滑動窗口的思路:
當我們題目要求找一個滿足要求的區間的時候,且這個區間的left和right指針,都只需要同向移動的時候,就可以使用滑動窗口,這個區間可以變長,變短,但是雙指針一定是同向移動即可!
所以滑動窗口的題目一般分別以下3步:
窗口定義:用?
left
?和?right
?指針表示當前窗口的左右邊界。移動規則:
進窗口(
right++
):當滿足條件時,擴大窗口以包含新元素。出窗口(
left++
):當不滿足條件時,收縮窗口以排除左側元素。由1,2可知,left和right都是同向移動(一般是向右)
統計結果:在移動過程中,根據題目要求記錄最優解(如最長/最短子數組)。
注:有時候是出窗口后再判斷更新,有時候是進窗口就可以更新,視題目而定!
一:題目
解釋:找一個最短的連續子數組的和 >=taget
二:算法
①:暴力
暴力解法的時間復雜度:N^3?
a:枚舉所有可能的子數組:一個長度為 n 的數組有 O(n^2) 個子數組(起點有 n 種選擇,終點有 n 種選擇,但實際是 n(n+1)/2,即 O(n^2))。
b:計算每個子數組的和:對于每個子數組,需要遍歷其所有元素求和。最壞情況下(子數組長度為 n),求和的時間復雜度是 O(n)。
c:所以:總時間復雜度為 O(n) × O(n) × O(n) = O(n^3)。
暴力能優化的點:
講暴力就是因為要對其進行優化,而優化過后就會發現其能用滑動窗口的思想來解決!
數組:[2,3,1,2,4,3]
當left 為2 right為2的時候 此時子數組和為8,如果按照暴力,此時我們的left會往走一個,然后right再回到left的位置向后繼續遍歷
優化1:但是其實我們right不用再動,只用left++即可,此時若是仍滿足要求,則更新長度即可,反之不滿足,則right++即可!
優化2:當left為更新為3的時候 此時我們right是指向2的 此時right可以不先回退! 先更新得知和為6,若此時的和仍大于等于t(7) 則更新區間長度,然后left直接再++ !; 反之小于t則right++
所以,綜上所述,次此題是一個雙指針同向移動的題目,所以用滑動窗口來解決!
②:滑動窗口
采取和滑動窗口之后,我們的雙指針最多只用遍歷數組一遍,所以時間復雜度為O(N)
三:代碼
class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int left = 0,right=0,len = INT_MAX,sum=0;for(;right<nums.size();right++){sum+=nums[right];//窗口總值++while(sum>=target)//窗口符合要求{len=min(len,(right-left+1));//取區間最小值去更新lensum-=nums[left];//出窗口 減去left的值 left++;//left++}}return (len==INT_MAX?0:len);//為INT_MAX代表此題無解,則返回0}
};
易錯點:
①:當窗口滿足要求的時候,一定是while循環,然后出一次窗口,判斷一次是否窗口還符合要求,符合則繼續出窗口,直到窗口不符合要求
②:更新結果,不是窗口滿足要求就更新到len,而是把當前次滿足要求的結果和之前的len取較小值去更新
③:len一開始直接給個最大值,因為我們求得是區間的最小值。滑動窗口的題目,讓你求最小你就給INT_MAX,讓你求最大值,你初識為0,準沒錯!