Sliding Window Algorithm(滑動(dòng)窗口算法)分析與實(shí)踐

學(xué)習(xí)如何使用Sliding Window Algorithm 攻克相關(guān)的Leetcode算法題。Leetcode上有若干滑動(dòng)窗口問題,網(wǎng)絡(luò)協(xié)議上也廣泛使用了滑動(dòng)窗口算法,可見這個(gè)算法的重要性。

本文參考:
1.https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/92007/Sliding-Window-algorithm-template-to-solve-all-the-Leetcode-substring-search-problem.
2.https://stackoverflow.com/questions/8269916/what-is-sliding-window-algorithm-examples
3.http://www.codingalpha.com/sliding-window-algorithm-c-program/


什么是滑動(dòng)窗口算法居夹?
The Sliding Problem contains a sliding window which is a sub – list that runs over a Large Array which is an underlying collection of elements.

假設(shè)有數(shù)組[a b c d e f g h]
一個(gè)大小為3的滑動(dòng)窗口在其上滑動(dòng),則有:
[a b c]
  [b c d]
    [c d e]
      [d e f]
        [e f g]
          [f g h]

滑動(dòng)窗口算法對(duì)比與分析
——待添加


滑動(dòng)窗口問題實(shí)例
一、FInd All Anagrams in a String

分析:對(duì)于string s 和 string t准脂,查找s中t的同字母異序詞子序列劫扒。那么這個(gè)子序列很明顯有三點(diǎn)非常明顯的特征:

  • 是s的子序列

  • 包含t中所包含的全部字符(包括重復(fù)的)

  • 子序列長(zhǎng)度與t相同

我們實(shí)現(xiàn)算法的最終目標(biāo)就是:判斷以上三個(gè)條件是否成立。

條件1和條件3無疑很好判斷意狠,但對(duì)于條件2粟关,如果使用嵌套循環(huán)的方式暴力解決,時(shí)間復(fù)雜度將是O(n*m).n為s的規(guī)模环戈,m為t的規(guī)模。

而滑動(dòng)窗口算法就是為了能夠高效的判斷該條件澎灸。

思路:在s上伸縮滑動(dòng)一個(gè)窗口院塞,(注意,不止包括整體的滑動(dòng)——即左右邊界同方向相同距離移動(dòng)性昭,也包括伸縮——即一個(gè)邊界動(dòng)一個(gè)邊界不動(dòng))拦止,那么必然滿足條件1,接下來如果由該窗口得到的子序列滿足條件2糜颠,且滿足條件3汹族,那么保存窗口左邊界作為結(jié)果之一。然后其兴,繼續(xù)伸縮滑動(dòng)窗口顶瞒,直至得到全部結(jié)果。

具體來說:

  1. 雙指針begin,end——記錄滑動(dòng)窗口的左右邊界元旬。

  2. 一個(gè)Hash表——記錄的t中的所有字符(去重)以及每個(gè)字符的出現(xiàn)次數(shù)榴徐。原因:由于t中可能包含重復(fù)字符,那么不僅要依次判斷窗口子序列是否包含t中某個(gè)字符匀归,還要判斷該字符出現(xiàn)的次數(shù)是否與在t中相同坑资。既然字符本身和出現(xiàn)次數(shù)相關(guān)聯(lián),那么就可以用一對(duì)鍵值對(duì)來表示穆端,所以可使用Hash表來保存t中的字符和出現(xiàn)頻率袱贮。C++中,我們用unordered_map<char, int> map;

  3. 一個(gè)計(jì)數(shù)器count体啰,記錄t中包含的字符數(shù)(去重后)攒巍,即需要判斷是否存在于t的字符。

  4. 令begin = 0, end = 0;移動(dòng)右邊界狡赐,每當(dāng)發(fā)現(xiàn)一個(gè)字符存在于t中窑业,遞減該字符在Hash表中出現(xiàn)頻次,即<key,value>中value的值枕屉,遞減至0時(shí)常柄,說明該窗口子序列中至少包含了與t中相同個(gè)數(shù)的該字符,那么此時(shí)遞減count計(jì)數(shù)器,表示該字符的判斷已完成西潘,需要判斷的字符數(shù)-1.

  5. 以此類推卷玉,不斷拓展右邊界,直至count為0喷市,表示窗口序列中已經(jīng)至少包含了t中所有字符(包括重復(fù)的)相种。

  6. 分析此時(shí)的窗口子序列,t是該序列的子集品姓,條件2已滿足寝并。如果兩者長(zhǎng)度相同,即滿足條件3腹备,那么它的左邊界begin就是我們想要的結(jié)果之一了衬潦。但我們不會(huì)一直那么幸運(yùn),這時(shí)就需要收縮窗口的左邊界植酥,即end不動(dòng)镀岛,begin向右移動(dòng)遍歷該子序列,直至找到t中包含的字符友驮,此時(shí)再次計(jì)算end-begin的值漂羊,與t長(zhǎng)度比較,判斷是否是想要的結(jié)果卸留。而找到上述字符后走越,字符頻次加1,如加1后該字符頻次仍小于0艾猜,說明該字符有冗余买喧,而出現(xiàn)頻次大于0,則count加1匆赃,這是告訴我們有一個(gè)字符需要重新被判斷了淤毛,因?yàn)闊o論它是不是我們想要的,都不能再用了算柳,需要繼續(xù)向右拓展窗口從新找起低淡。

  7. 當(dāng)count != 0時(shí),繼續(xù)向右拓展窗口瞬项,直至count為0蔗蹋,然后判斷條件3的同時(shí),向右移動(dòng)begin遍歷子序列囱淋,直至count != 0,以此類推猪杭。

(為了弄清思路的細(xì)節(jié),寫了一大堆的文字妥衣,實(shí)在是辛苦皂吮。)

上面是文字形式的分析戒傻,如果看不懂,那么應(yīng)結(jié)合圖表推演分析蜂筹。且真正分析算法問題時(shí)需纳,應(yīng)該在腦中或者草稿紙上構(gòu)思出具體的圖畫。

//該例子來自于leetcode
Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]

Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
滑動(dòng)窗口序列變化示意圖
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        
        vector<int> result;
        
        if(s.empty() || p.empty()) return result;
        if(p.size() > s.size()) return result;
        
        unordered_map<char, int> map;
        
        for(char c : p)
        {
            map[c] = map[c] + 1;
        }
        
        size_t count = map.size();
        
        int begin = 0, end = 0;
        
        while(end < s.size())
        {
            if(map.find(s.at(end)) != map.end())
            {
                map[s.at(end)]--;
                if(map[s.at(end)] == 0){ count--; }
            }
            ++end;
            
            while(count == 0)
            {
                if(map.find(s.at(begin)) != map.end())
                {
                    map[s.at(begin)]++;
                    if(map[s.at(begin)] > 0){ count++; }
                }
                
                if(end - begin == p.size())
                {
                    result.push_back(begin);
                }
                ++begin;
            } 
        }
        
       return result;
        
    }
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艺挪,一起剝皮案震驚了整個(gè)濱河市不翩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麻裳,老刑警劉巖口蝠,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異津坑,居然都是意外死亡亚皂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門国瓮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狞谱,你說我怎么就攤上這事乃摹。” “怎么了跟衅?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵孵睬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我伶跷,道長(zhǎng)掰读,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任叭莫,我火速辦了婚禮蹈集,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雇初。我一直安慰自己拢肆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布靖诗。 她就那樣靜靜地躺著郭怪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刊橘。 梳的紋絲不亂的頭發(fā)上鄙才,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音促绵,去河邊找鬼攒庵。 笑死嘴纺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叙甸。 我是一名探鬼主播颖医,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼裆蒸!你這毒婦竟也來了熔萧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤僚祷,失蹤者是張志新(化名)和其女友劉穎佛致,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辙谜,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡俺榆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了装哆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罐脊。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜕琴,靈堂內(nèi)的尸體忽然破棺而出萍桌,到底是詐尸還是另有隱情,我是刑警寧澤凌简,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布上炎,位于F島的核電站,受9級(jí)特大地震影響雏搂,放射性物質(zhì)發(fā)生泄漏藕施。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一凸郑、第九天 我趴在偏房一處隱蔽的房頂上張望裳食。 院中可真熱鬧,春花似錦线椰、人聲如沸胞谈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烦绳。三九已至,卻和暖如春配紫,著一層夾襖步出監(jiān)牢的瞬間径密,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工躺孝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留享扔,地道東北人底桂。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像惧眠,于是被迫代替她去往敵國(guó)和親籽懦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • 依稀記得去年元宵氛魁,我跟家里的那個(gè)人吵架了暮顺,我一個(gè)人賭氣跑到街上,和著眼淚吃完了一碗元宵秀存。然后悻悻地回到了家捶码。今年無...
    我的摳腳大漢閱讀 199評(píng)論 0 0
  • 這夜在順德佬還沒把菜吃完,一個(gè)個(gè)就喊吃撐了或链。恰巧還有兩個(gè)居然趕到惫恼,來?yè)?dān)那消滅殘羹的重任。 不過也只是給一個(gè)留了菜澳盐,...
    楓嶺舊客閱讀 401評(píng)論 2 3
  • 問題背景 —— 一位陷入兩難困境的大學(xué)生朋友說:因高中懶散,只考取了普通一本旬蟋,現(xiàn)就讀于國(guó)內(nèi)非211學(xué)校的金融系。自...
    上官文商閱讀 1,387評(píng)論 1 4
  • 前言 在iOS開發(fā)中革娄,由于各個(gè)屏幕寬度不一樣倾贰,所以適配起來多少有些麻煩。本文拦惋,先介紹一下適配方法匆浙,然后介紹一下這個(gè)...
    David_Cap閱讀 2,563評(píng)論 8 26