算法題套路總結(jié)(一)——鏈表

最近也做了很多題目容劳,但是回過頭一看發(fā)現(xiàn)好多題目雖然當時是我獨立思考出來的祟辟,但是我又忘了該怎么做了,又得花好長時間是思考。不過想來想去發(fā)現(xiàn)其實大部分題目還是有套路的洪规,所以我覺得是時候去總結(jié)一下這些套路印屁。這是個系列文章,將會總結(jié)一些常見題型的套路斩例。第一篇先說說鏈表雄人。我遇見的所有算法題目所涉及到的鏈表,都是單鏈表念赶,因此這里也只說單鏈表础钠。

單鏈表其實就是一個data加上一個next指針。由于一個節(jié)點只通過next指針保存了它的下一個節(jié)點晶乔,失去了它的前驅(qū)節(jié)點信息珍坊,因此幾乎所有單鏈表題目都是在前驅(qū)節(jié)點做文章。同時正罢,單鏈表數(shù)據(jù)結(jié)構(gòu)通常長度未知阵漏,很多題目也會在長度上做文章》撸基本上思考鏈表題目就這么兩個思路下手履怯。

圍繞這兩個問題,鏈表大致有以下幾種經(jīng)典題型:

  • 雙指針
  • 模擬高精度加減法
  • 翻轉(zhuǎn)鏈表(全部or部分)

雙指針

針對于雙指針裆泳,實際上更細化也分兩種:

  • 快慢指針
  • 前后指針

比如說:

  • 19. 刪除鏈表的倒數(shù)第N個節(jié)點叹洲,鏈表涉及到長度,馬上應(yīng)該聯(lián)想到雙指針工禾。由于長度未知运提,倒數(shù)第N個怎么找?兩個指針闻葵,第一個先走N步民泵,第二個原地不動。然后一起遍歷槽畔,當前面指針到最后時栈妆,后面的指針就指向倒數(shù)第N

  • 61. 旋轉(zhuǎn)鏈表,旋轉(zhuǎn)k相當于把尾節(jié)點連到頭結(jié)點厢钧,然后在倒數(shù)第k個節(jié)點處斷開鳞尔。但是這里需要遍歷一次鏈表取得總長度n,因為k很可能非常大早直,需要對n取模寥假。也是一個經(jīng)典的前后指針的運用

  • 環(huán)形鏈表,判斷鏈表是否有環(huán)霞扬。鏈表有環(huán)說明next永遠不為None糕韧,此時采用快慢指針拾给,一個指針快(一次走2步)一個指針慢(一次走1步),如果有環(huán)兔沃,快指針某個時刻就會追上滿指針(跑步超圈)。如果快指針走到None節(jié)點级及,說明無環(huán)乒疏。

針對鏈表的環(huán),其實也有兩個經(jīng)典題目饮焦,一個是求環(huán)的起點142. 環(huán)形鏈表 II
怕吴,一個是求環(huán)的長度。
求環(huán)的長度其實可以轉(zhuǎn)化成小學(xué)數(shù)學(xué)的追及問題县踢。當快慢指針第一次相遇時转绷,此時節(jié)點肯定在環(huán)上某個位置。我們以此為起點繼續(xù)走硼啤,同時記錄步數(shù)t议经。當快慢指針再次相遇時,相當于速度為2的經(jīng)過t秒比速度為1的多跑了一圈谴返,2*t-1*t=t煞肾,因此環(huán)的長度就是t
而求環(huán)的起點則稍微需要畫個圖來理解。(暫時缺圖嗓袱,后面補籍救,證明過程在圖上)總之結(jié)論就是,當快慢指針第一次相遇后渠抹,慢指針到環(huán)的起點的距離和鏈表頭指針到環(huán)起點距離相等蝙昙。也就是說,此時利用一個新的指針梧却,從頭開始走奇颠,當和慢指針相遇時,該節(jié)點就是環(huán)的起點篮幢。

環(huán)形鏈表的一個變種就是求兩個鏈表的交點大刊,比如160. 相交鏈表。這道題表面上看起來有兩個鏈表三椿,不過如果做一個輔助線缺菌,比如把B鏈表首尾相連,也就是讓鏈表的末節(jié)點指向B鏈表的表頭搜锰,那么這道題就變成了求單鏈表的環(huán)的起點伴郁。當然這種思路就需要做題時積累了,臨場想的話還是稍微有點費勁蛋叼。

翻轉(zhuǎn)鏈表

翻轉(zhuǎn)鏈表就是很直接的題目焊傅,主要是考實現(xiàn)而不是考算法剂陡。翻轉(zhuǎn)鏈表的題目就比較種類繁多了,但各種翻轉(zhuǎn)都萬變不離其宗狐胎。只要掌握了翻轉(zhuǎn)整個鏈表的方法鸭栖,剩下大部分的都是花式處理邊界case。

fn reverse_list(mut head: Option<Box<ListNode>>) ->   
  Option<Box<ListNode>> {
  let mut new_head = None;
  while let Some(node) = head.take() {
    let new_node = ListNode{
        val: node.val,
        next: new_head.take(),
    };
    new_head = new_node;
    head = node.next;
  }
  new_head
}

以上是通過新建鏈表來進行翻轉(zhuǎn)握巢,實際上還可以原地翻轉(zhuǎn)晕鹊,Rust不太方便實現(xiàn),Go的偽代碼如下:

func reverseLinkedList(head *ListNode) *ListNode {
  if head == nil {
    return nil
  }
  var newHead *ListNode
  cur := head
  for cur != nil {
    next := cur.Next
    cur.Next = newHead
    newHead = cur
    cur = next
  }
  return newHead
}

這種原地翻轉(zhuǎn)實際上只是改變了節(jié)點指針的指向暴浦,更簡單了溅话。

由于直接翻轉(zhuǎn)鏈表很簡單,因此大部分題目都是花式翻轉(zhuǎn)歌焦,比如:

  • 25. K 個一組翻轉(zhuǎn)鏈表24. 兩兩交換鏈表中的節(jié)點(相當于K=2),當我們在翻轉(zhuǎn)鏈表中的連續(xù)k個節(jié)點時飞几,實際上和翻轉(zhuǎn)整個鏈表沒有區(qū)別。但是需要注意的是独撇,翻轉(zhuǎn)完的鏈表需要接到之前的鏈表后面屑墨,即pre.Next = newHead,同時纷铣,因為要繼續(xù)翻轉(zhuǎn)接下來的k個绪钥,因此還要記錄翻轉(zhuǎn)后鏈表的尾節(jié)點。當發(fā)現(xiàn)最后一次不足k個時关炼,還要把已經(jīng)翻轉(zhuǎn)的鏈表再翻轉(zhuǎn)回去程腹。

  • 234. 回文鏈表,判斷一個鏈表是否是回文的儒拂,利用快慢指針找到中點寸潦,然后把后半部分翻轉(zhuǎn)。如果是回文的社痛,翻轉(zhuǎn)之后后半部分和前半部分應(yīng)該是一樣的

  • 143. 重排鏈表见转,要把L0->L1->L2->L3->L4變成L0->L4->L1->L3->L2,其實相當于把鏈表前一半不動L0->L1->L2蒜哀,后一半翻轉(zhuǎn)L4->L3斩箫,然后把翻轉(zhuǎn)后的節(jié)點插入到前一半鏈表的縫隙中L0-> (L4) -> L1-> (L3) -> L2。關(guān)鍵詞一半撵儿、翻轉(zhuǎn)乘客。因此,利用快慢指針找到前一半淀歇,然后把后一半翻轉(zhuǎn)偷霉,最后再插空洋措。

翻轉(zhuǎn)鏈表變種題目盆均,大多數(shù)可能需要開辟額外空間或者建立新的虛擬鏈表,最終再拼接回去缀匕。比如:

  • 86. 分隔鏈表,給鏈表重新排序碰逸,小于x的元素要在大于等于x的元素的前面乡小,剩下的元素相對順序不變。這道題就可以建立兩個虛擬鏈表饵史,小于x的放到before鏈表中劲件,大于等于的放到after鏈表,最終再把after放到before后面约急。
  • 328. 奇偶鏈表,同樣建立兩個虛擬鏈表苗分,一個保存奇數(shù)個節(jié)點一個保存偶數(shù)個厌蔽,最后合并回去
  • 725. 分隔鏈表,先求出鏈表總長度n摔癣,然后計算每個部分要放幾個元素奴饮,前n%k個部分要多一個元素,直接遍歷即可择浊。

高精度運算

這類題不多戴卜,但是其實解法很簡單。因為加減法涉及到進位琢岩,所以先翻轉(zhuǎn)鏈表投剥,然后進行加法操作即可。

總結(jié)

經(jīng)過上面的總結(jié)担孔,其實鏈表基本就這么些題型江锨,只要掌握了這些題型和核心解題思路,拿起雙指針和翻轉(zhuǎn)兩大武器糕篇,基本上就不怕鏈表的題目了啄育。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拌消,隨后出現(xiàn)的幾起案子挑豌,更是在濱河造成了極大的恐慌,老刑警劉巖墩崩,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氓英,死亡現(xiàn)場離奇詭異,居然都是意外死亡鹦筹,警方通過查閱死者的電腦和手機债蓝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盛龄,“玉大人饰迹,你說我怎么就攤上這事芳誓。” “怎么了啊鸭?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵锹淌,是天一觀的道長。 經(jīng)常有香客問我赠制,道長赂摆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任钟些,我火速辦了婚禮烟号,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘政恍。我一直安慰自己汪拥,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布篙耗。 她就那樣靜靜地躺著迫筑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宗弯。 梳的紋絲不亂的頭發(fā)上脯燃,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音蒙保,去河邊找鬼辕棚。 笑死,一個胖子當著我的面吹牛邓厕,可吹牛的內(nèi)容都是我干的坟募。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼邑狸,長吁一口氣:“原來是場噩夢啊……” “哼懈糯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起单雾,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤赚哗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后硅堆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屿储,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年渐逃,在試婚紗的時候發(fā)現(xiàn)自己被綠了够掠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡茄菊,死狀恐怖疯潭,靈堂內(nèi)的尸體忽然破棺而出赊堪,到底是詐尸還是另有隱情,我是刑警寧澤竖哩,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布哭廉,位于F島的核電站,受9級特大地震影響相叁,放射性物質(zhì)發(fā)生泄漏遵绰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一增淹、第九天 我趴在偏房一處隱蔽的房頂上張望椿访。 院中可真熱鬧,春花似錦虑润、人聲如沸成玫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虽画,卻和暖如春舞蔽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背码撰。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工渗柿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脖岛。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓朵栖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柴梆。 傳聞我的和親對象是個殘疾皇子陨溅,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

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