鏈表翻轉(zhuǎn)問(wèn)題

問(wèn)題:Reverse Linked List

Reverse a singly linked list.

Input:

  • 鏈表頭結(jié)點(diǎn) :: ListNode

Output:

  • 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode

Intuition:

這道題是鏈表翻轉(zhuǎn)的最最基本的題型了(沒(méi)有之一)。解法也是非常直接的翻轉(zhuǎn)pointer就好,如果非要說(shuō)tricky的地方就是翻轉(zhuǎn)的時(shí)候注意存儲(chǔ)下之前依賴翻轉(zhuǎn)pointer的其他node。

但是,你敢信我剛開(kāi)始刷題的時(shí)候花了一下午時(shí)間在這道題上,最后還是沒(méi)搞清楚pointer該指哪兒么?是的,對(duì)于這種大部分人認(rèn)為太簡(jiǎn)單了面試不會(huì)考的pointer變換的題目(包括樹(shù)的題型)本渣的水平大概可以形容為左轉(zhuǎn)左轉(zhuǎn)左轉(zhuǎn)左轉(zhuǎn)原來(lái)是個(gè)圈呦(ノへ ̄、)。好了廢話打住,那么現(xiàn)在就來(lái)做個(gè)翻轉(zhuǎn)鏈表的小小歸納。

首先我們需要一個(gè)scanner來(lái)掃描所有的node記為cur。另外還需要cur兩邊的node來(lái)記錄上下關(guān)系,記為pre和next。那么剛開(kāi)始的情況應(yīng)該是這樣的:

image.png

之后,很明顯我們需要翻轉(zhuǎn)那個(gè)紅箭頭,但是如果翻轉(zhuǎn)它,那么他原來(lái)指向的node就無(wú)法access了,那就需要一個(gè)變量來(lái)記錄下原來(lái)指向的node,這里用next來(lái)保存。

接下來(lái)翻轉(zhuǎn)箭頭
cur.next = pre
那么這部分就翻轉(zhuǎn)成功了,所有的node指針往后移動(dòng)一位,繼續(xù)下一個(gè)部分的翻轉(zhuǎn):

image.png

最后,pre作為新的頭結(jié)點(diǎn)返回。

Code:

public ListNode reverseLL(TreeNode head){
  ListNode cur = head;
  ListNode pre = null;
  ListNode next = null;
  while(cur != null){
    next = cur.next; 
    cur.next = pre; //reverse pointer
    //move foward to next node
    pre = cur;
    cur = next;
  }
  return pre;
}

問(wèn)題:Reverse Linked List II

Reverse a linked list from position m to n. Do it in-place and in one-pass.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.

Input:

  • 鏈表頭結(jié)點(diǎn) :: ListNode
  • 翻轉(zhuǎn)起始位置m :: Integer
  • 翻轉(zhuǎn)終了位置n :: Integer

Output:

  • 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode

Intuition:

剛剛那道題是不是小case呀,那么增加點(diǎn)難度,只翻轉(zhuǎn)第m個(gè)到第n個(gè)節(jié)點(diǎn)的部分。
最直接的想法還是需要三個(gè)指針,cur, pre, next. 但是只有當(dāng)cur到達(dá)起始點(diǎn)時(shí)才開(kāi)始翻轉(zhuǎn),那么很自然的想到需要維持一個(gè)counter。而同樣的翻轉(zhuǎn)停止的部分也需要一個(gè)counter,當(dāng)這個(gè)counter等于m - n的時(shí)候停止翻轉(zhuǎn)。
最后,中間翻轉(zhuǎn)部分結(jié)束后跟原來(lái)鏈表中的起止點(diǎn)相連就可以了.
舉個(gè)??:
m = 2, n = 4, 先找到起始點(diǎn),p在m-1的位置停下,下一個(gè)位置就是pre,依次的cur,next的部分也可以確定,那么我們要翻轉(zhuǎn)的指針就是cur和next之間的那個(gè):

image.png

翻轉(zhuǎn)次數(shù)是m-n = 2 次,第一次翻轉(zhuǎn):

image.png

第二次翻轉(zhuǎn):

image.png

最后接回原來(lái)的起止點(diǎn)

image.png

Code:

TC:(n) SC:O(1)

public TreeNode reverseLLII(TreeNode head, int m, int n){
  TreeNode  dummy = new TreeNode(-1);
  dummy.next = head;
  //scanner
  TreeNode p = dummy;
  int cnt1 = 0;
  while (cnt1 < m -1){
    p = p.next;
    cnt1++;
  }

  //initial pre and cur
  ListNode pre = p.next;
  ListNode cur = pre.next;
  int cnt2 = n - m; //reverse n - m times
  while(cnt2 > 0){
    ListNode next = cur.next;
    cur.next = pre;
    pre = cur;
    cur = next;
    cnt2--;
  }
  p.next.next = cur;
  p.next = pre;
  return dummy.next;
}

再抽象一點(diǎn)點(diǎn),我們?cè)囋嚹懿荒軇?dòng)態(tài)的reverse,也就是每一個(gè)小部分翻轉(zhuǎn)后都立刻與原鏈表鏈接而不是等翻轉(zhuǎn)完全結(jié)束后再連接原來(lái)的鏈表。

首先記錄把pre與右邊界相連,注意這里的右邊界不是指整個(gè)m ~ n的右邊界,而是指最小的翻轉(zhuǎn)section的局部右邊界,比如2 -> 3的局部右邊界就是4.

image.png

進(jìn)行翻轉(zhuǎn)

image.png

連接好左邊界

image.png

繼續(xù)移動(dòng)到下一個(gè)node

image.png

code翻轉(zhuǎn)改動(dòng)的部分是:

ListNode pre = p.next; //leftBound.next
ListNode cur = pre.next;
while(cnt2 > 0){
   pre.next = cur.next;
   cur.next = p.next;
   p.next = cur;
   cur = pre.next;
   cnt2--;
  }

問(wèn)題:Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

Input:

  • 鏈表頭結(jié)點(diǎn) :: ListNode
  • 翻轉(zhuǎn)間隔k :: Integer

Output:

  • 翻轉(zhuǎn)后鏈表頭結(jié)點(diǎn) :: ListNode

Intuition:

挑戰(zhàn)下極限吧,這道題應(yīng)該是我見(jiàn)過(guò)鏈表翻轉(zhuǎn)最高難度的代表啦,弄懂這道題,鏈表翻轉(zhuǎn)應(yīng)該就沒(méi)多大問(wèn)題了。

還是借助之前兩題的思想counter和in place翻轉(zhuǎn)。不同的是counter指示的時(shí)機(jī)是什么?每遇到某幾個(gè)數(shù)就去做某某事,這個(gè)條件實(shí)現(xiàn)最簡(jiǎn)單的方法是什么?mod對(duì)不對(duì)~ 嗯,大功告成,我們要改善的其實(shí)就是這么一點(diǎn)點(diǎn)。

Code:

TC:(n) SC:O(1)

public ListNode reverseK(TreeNode head, int k){
  if (head == null || k == 1){
    return head;
  }
  ListNode p = head;
  ListNode dummy = new ListNode(-1);
  dummy.next = head;
  ListNode leftbound = dummy;
  int cnt = 0;
  while(p != null){
    cnt++;
    if(cnt % k == 0){//find reverse section
      ListNode pre = helper(leftBound, p.next);
      p = pre.next;
    }else{
      p = p.next;
    }
  }
  return 
}

public ListNode helper(ListNode leftBound, ListNode rightBound){
  ListNode pre = leftBound.next; 
  ListNode cur = pre.next;
  while(cur != rightBound){
    pre.next = cur.next;
    cur.next = leftBound.next;
    leftBound.next = cur;  
    cur = pre.next;
  }
  return pre;
}

Reference

https://leetcode.com/problems/reverse-linked-list/description/
https://leetcode.com/problems/reverse-linked-list-ii/description/
https://leetcode.com/problems/reverse-nodes-in-k-group/description/
https://discuss.leetcode.com/topic/12364/non-recursive-java-solution-and-idea/2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

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

  • //leetcode中還有花樣鏈表題,這里幾個(gè)例子,冰山一角 求單鏈表中結(jié)點(diǎn)的個(gè)數(shù)----時(shí)間復(fù)雜度O(n)這是最...
    暗黑破壞球嘿哈閱讀 1,524評(píng)論 0 6
  • Single Linked List 相比較另一個(gè)基本的數(shù)據(jù)結(jié)構(gòu)array,linked list有幾個(gè)優(yōu)勢(shì):尺寸...
    dol_re_mi閱讀 8,201評(píng)論 0 3
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,761評(píng)論 0 33
  • 2. Add Two Numbers 先初始化兩個(gè)結(jié)點(diǎn),一個(gè)用來(lái)做head,一個(gè)作為指引node不斷向下延續(xù)的指針...
    Morphiaaa閱讀 927評(píng)論 0 0
  • 1.基本函數(shù):Java Kotlin 2.傳參數(shù)函數(shù):Java Kotlin 3.傳參數(shù)帶默認(rèn)值函數(shù):Java K...
    sweetheast閱讀 556評(píng)論 0 3