【LeetCode209.長(zhǎng)度最小的子數(shù)組】——雙指針法、二分查找法

209.長(zhǎng)度最小的子數(shù)組

給定一個(gè)含有 n 個(gè)正整數(shù)的數(shù)組和一個(gè)正整數(shù) target 肆汹。

找出該數(shù)組中滿足其和 ≥ target 的長(zhǎng)度最小的 連續(xù)子數(shù)組 [numsl, numsl+1, ..., numsr-1, numsr] 终吼,并返回其長(zhǎng)度。如果不存在符合條件的子數(shù)組油宜,返回 0 。

示例 1:

輸入:target = 7, nums = [2,3,1,2,4,3]
輸出:2
解釋:子數(shù)組 [4,3] 是該條件下的長(zhǎng)度最小的子數(shù)組屑彻。

示例 2:

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

示例 3:

輸入:target = 11, nums = [1,1,1,1,1,1,1,1]
輸出:0

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

進(jìn)階:

  • 如果你已經(jīng)實(shí)現(xiàn) O(n) 時(shí)間復(fù)雜度的解法, 請(qǐng)嘗試設(shè)計(jì)一個(gè) O(n log(n)) 時(shí)間復(fù)雜度的解法验庙。

209. 長(zhǎng)度最小的子數(shù)組 - 力扣(LeetCode)

思路:

要尋找符合條件的最小子數(shù)組,自然而然就可以想到通過把所有的子數(shù)組遍歷一遍社牲,找到符合要求的粪薛,再比較其中的長(zhǎng)度最小的子數(shù)組。這樣的話搏恤,要使用兩層for循環(huán)违寿,屬于暴力解法,時(shí)間復(fù)雜度較高熟空。

做這道題我們可以使用滑動(dòng)窗口的方法藤巢,其實(shí)和雙指針法是比較類似的。只不過移動(dòng)的是整個(gè)一個(gè)區(qū)間息罗,所以稱為滑動(dòng)窗口掂咒。

暴力解法:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; // 讓result等于一個(gè)極大的值,INT32_MAX為宏定義
        int sum = 0; // 存儲(chǔ)子序列的數(shù)值之和
        int subLength = 0; // 存儲(chǔ)子序列的長(zhǎng)度
        for (int i = 0; i < nums.size(); i++) { // 設(shè)置子序列起點(diǎn)為i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 設(shè)置子序列終止位置為j
                sum += nums[j];
                if (sum >= s) { // 一旦發(fā)現(xiàn)子序列和超過了s,更新result
                    subLength = j - i + 1; // 取子序列的長(zhǎng)度
                    result = result < subLength ? result : subLength; //比較更新result
                    break; //找到符合條件最短的子序列绍刮,退出循環(huán)
                }
            }
            // 如果result沒有被賦值的話温圆,就返回0,說明沒有符合條件的子序列
            return result == INT32_MAX ? 0 : result;
        }
    }
};

時(shí)間復(fù)雜度:O(n^2)

滑動(dòng)窗口法:

我們可以使用滑動(dòng)窗口法對(duì)時(shí)間復(fù)雜度進(jìn)行優(yōu)化孩革,不斷調(diào)節(jié)子序列的起始和終止位置岁歉。

設(shè)定兩個(gè)指針i和j,分別指向滑動(dòng)窗口的起始位置以及終止位置膝蜈。

這里我們就需要考慮滑動(dòng)窗口外層for循環(huán)中遍歷的應(yīng)該是窗口的起始位置還是終止位置锅移。

如果起始位置一直在移動(dòng)的話,不可避免的饱搏,我們?cè)谄鹗嘉恢妹看巫兓胺翘辏K止位置都需要對(duì)整條數(shù)組進(jìn)行一遍遍歷,若是這么做窍帝,那就與之前的暴力解法無異了努潘。

所以我們采用循環(huán)的索引表示滑動(dòng)窗口終止位置的方法,讓j先去不斷移動(dòng)坤学,用sum記錄此時(shí)窗口中的和疯坤,一旦sum的值大于等于目標(biāo)值,我們就可以對(duì)起始位置進(jìn)行更新深浮,縮小起始位置压怠,從而判斷是否存在更小長(zhǎng)度,符合條件的子數(shù)組飞苇。

class Solution {
public:
   //滑動(dòng)窗口
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX; //讓result取一個(gè)極大值
        int sum = 0; // 滑動(dòng)窗口數(shù)值之和
        int i = 0; // 滑動(dòng)窗口起始位置
        int subLength = 0; // 滑動(dòng)窗口的長(zhǎng)度
        for (int j = 0; j < nums.size(); j++) { //j指向滑動(dòng)窗口的末尾位置菌瘫,用來遍歷
            sum += nums[j];
            // 注意這里使用while,每次更新 i(起始位置)布卡,并不斷比較子序列是否符合條件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的長(zhǎng)度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 不斷變更i(子序列的起始位置)
            }
        }
        // 如果result沒有被賦值的話雨让,就返回0,說明沒有符合條件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

時(shí)間復(fù)雜度:O(2n) 可以視作 O(n)

二分查找法:

這種方法利用了之前所學(xué)到的二分查找法忿等,先創(chuàng)建一個(gè)數(shù)組sums用于存儲(chǔ)數(shù)組nums的前綴和栖忠。sums[i]表示nums[0]到nums[i-1]的元素和。

得到前綴和后贸街,對(duì)于每個(gè)開始下標(biāo)i庵寞,通過二分查找得到大于等于i的最小下標(biāo)bound,使得sums[bound]-sums[i-1]大于等于s薛匪。并實(shí)時(shí)更新子數(shù)組的最小長(zhǎng)度bound-(i-1)

這里使用二分查找的前提是前綴和數(shù)組sums是有序的捐川,由于原數(shù)組中都是正整數(shù),所以所得到的的前綴和數(shù)組也必定是遞增的逸尖,所以我們可以使用二分查找的方法古沥。

class Solution {
public:
   //二分查找
    int minSubArrayLen3(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) { //判斷數(shù)組為空的情況
            return 0;
        }
        int ans = INT_MAX; //先將結(jié)果值設(shè)置為一個(gè)極大值
        vector<int> sums(n + 1, 0);
        // 為了方便計(jì)算瘸右,令 size = n + 1 
        // sums[0] = 0 意味著前 0 個(gè)元素的前綴和為 0
        // sums[1] = A[0] 前 1 個(gè)元素的前綴和為 A[0]
        // 以此類推
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for (int i = 1; i <= n; i++) {
            int target = s + sums[i - 1];
            auto bound = lower_bound(sums.begin(), sums.end(), target); //使用現(xiàn)成的庫函數(shù)來實(shí)現(xiàn)這里二分查找大于等于某個(gè)數(shù)的第一個(gè)位置的功能
            if (bound != sums.end()) {
                ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

時(shí)間復(fù)雜度:O(nlogn)

后續(xù)也會(huì)堅(jiān)持更新我的LeetCode刷題筆記,歡迎大家關(guān)注我渐白,一起學(xué)習(xí)尊浓。
如果這篇文章對(duì)你有幫助逞频,或者你喜歡這篇題解纯衍,可以給我點(diǎn)個(gè)贊哦。
CSDN同步更新苗胀,歡迎關(guān)注我的博客:一粒蛋TT的博客_CSDN博客-LeetCode學(xué)習(xí)筆記,HTML+CSS+JS,數(shù)據(jù)結(jié)構(gòu)領(lǐng)域博主

往期回顧:
LeetCode977.有序數(shù)組的平方
LeetCode844.比較含退格的字符串
LeetCode283.移動(dòng)零
LeetCode27.移除元素
LeetCode26.刪除有序數(shù)組中的重復(fù)項(xiàng)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末襟诸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子基协,更是在濱河造成了極大的恐慌歌亲,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澜驮,死亡現(xiàn)場(chǎng)離奇詭異陷揪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)杂穷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門悍缠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人耐量,你說我怎么就攤上這事飞蚓。” “怎么了廊蜒?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵趴拧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我山叮,道長(zhǎng)著榴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任屁倔,我火速辦了婚禮脑又,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘汰现。我一直安慰自己挂谍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布瞎饲。 她就那樣靜靜地躺著口叙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗅战。 梳的紋絲不亂的頭發(fā)上妄田,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天俺亮,我揣著相機(jī)與錄音,去河邊找鬼疟呐。 笑死脚曾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的启具。 我是一名探鬼主播本讥,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鲁冯!你這毒婦竟也來了拷沸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤薯演,失蹤者是張志新(化名)和其女友劉穎撞芍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體跨扮,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡序无,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衡创。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帝嗡。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钧汹,靈堂內(nèi)的尸體忽然破棺而出丈探,到底是詐尸還是另有隱情,我是刑警寧澤拔莱,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布碗降,位于F島的核電站,受9級(jí)特大地震影響塘秦,放射性物質(zhì)發(fā)生泄漏讼渊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一尊剔、第九天 我趴在偏房一處隱蔽的房頂上張望爪幻。 院中可真熱鬧,春花似錦须误、人聲如沸挨稿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奶甘。三九已至,卻和暖如春祭椰,著一層夾襖步出監(jiān)牢的瞬間臭家,已是汗流浹背疲陕。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钉赁,地道東北人蹄殃。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像你踩,于是被迫代替她去往敵國和親诅岩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容