1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試必備 | 不可不會的反轉(zhuǎn)鏈表

        共 2682字,需瀏覽 6分鐘

         ·

        2020-09-24 18:38


        反轉(zhuǎn)鏈表這題真的是面試非常喜歡考的了,這題看起來簡單,但是能用兩種方法一遍 bug free 也是不容易的,面試的時候可以篩下來一大批人,無論是對 junior 還是 senior 面試都很愛考。

        今天就帶你梳理清楚思路,思路清楚了才能寫碼如有神。


        題目

        這是從力扣中文站上截下來的,但是這個輸出不太形象。

        對鏈表的反轉(zhuǎn),并不是要把它實際翻個個,只是動一動 next 指針就好了。

        什么意思呢?

        我們先看對數(shù)組進(jìn)行反轉(zhuǎn)。

        數(shù)組是一個物理上連續(xù)存儲的數(shù)據(jù)結(jié)構(gòu),反轉(zhuǎn)之后原來放 1 的位置就變成了放 5.

        但是鏈表并不是,因為鏈表在物理上是不連續(xù)的,它的每個單元 ListNode 是通過 next 指針連接在一起的,而每個 ListNode 之間在內(nèi)存里并不一定是挨著的。

        所以反轉(zhuǎn)鏈表,就不是非要把 1 的位置放 5,因為它們想在哪在哪。

        那么怎么保證這個順序呢?

        • 就是 next 指針。

        沿著 next 指針的方向走下去,就是鏈表的順序。這也就保證了,只要我們拿到了頭節(jié)點,就掌控了整個 LinkedList.

        那么題目中的例子,形象點是這個樣子滴:

        也就是元素自己不用動,只需要動動小指針,就是反轉(zhuǎn)了。




        遞歸解法


        遞歸的三步驟大家還記得嗎?

        Base case + 拆解 + 組合

        不記得的趕緊在公眾號內(nèi)回復(fù)「遞歸」二字,獲取遞歸的入門篇詳解。

        那么我們來看這個題的:

        base case:

        當(dāng)只有一個 node,或者沒有 node 了唄,也就是

        if(node?==?null?||?node.next?==?null)?{
        ??return?node;
        }

        其實呢,只剩一個 node 的時候嚴(yán)格來講并不是 base case,而是 corner case,

        因為它本可以再 break down 到 node == null 的,但因為后面有對 node.next 的 dereference 操作,所以不能省略。

        拆解:

        遞歸的拆解就是把大問題,分解成小一點點的問題,直到 base case 可以返回,進(jìn)行第三步的組合。

        那么這里就是

        組合:

        組合的意思是,假設(shè)我們能夠拿到小問題的解,那么用小問題的解去構(gòu)造大問題的解。

        那么這道題如何構(gòu)造呢?

        這里很明顯,在 2 后面接上 1 就行了。

        但是怎么拿到 2 呢?

        別忘了,原問題里,此時還有 1 指向 2 呢~

        也就是 node1.next = node2

        然后把 2 指向 1:node2.next = node1

        合起來就是:node1.next.next = node1

        思路清楚就不繞,看著覺得繞的就是沒想清楚哼~

        代碼

        遞歸的代碼寫起來都很簡潔:

        class?Solution?{
        ????public?ListNode?reverseList(ListNode?head)?{
        ????????if(head?==?null?||?head.next?==?null)?{
        ????????????return?head;
        ????????}
        ????????ListNode?newHead?=?reverseList(head.next);
        ????????head.next.next?=?head;
        ????????head.next?=?null;
        ????????return?newHead;
        ????}
        }

        時間復(fù)雜度

        我們在「遞歸」這篇文章里說過,遞歸的時間復(fù)雜度分析方法就是把遞歸樹畫出來,每個節(jié)點的時間加起來就行了。

        這個遞歸樹是一個很簡單的單項鏈表,每個節(jié)點上做的就是那三行代碼,也就是「組合」做的事,即 O(1) 的時間,總共有 n 個節(jié)點,那么總的時間就是 O(n).

        空間復(fù)雜度

        那看遞歸樹也很明顯了,每一層也就用了點小變量,是 O(1),所以總的空間共是 O(n).



        Iterative 解法


        (誰能告訴我這個中文的專業(yè)說法。。

        Iterative 的思路就是:
        過一遍這個 Linked List,邊過邊把這個 node 的 next 指針指向前面那個 node,直到過完全部。

        這樣說太抽象,面試時也是,直接過例子。

        那也就是把 1 的 next 指針翻過來指向 NULL;
        把 2 的 next 指針翻過來指向 1;
        把 3 的 next 指針翻過來指向 2;
        ...

        所以我們還需要一個變量來記錄當(dāng)前 node 的前一個 node,不妨設(shè)為 prev.

        同時呢,一旦我們把指針翻轉(zhuǎn)過去,后面的那個 node 就丟了有木有!所以還需要有個額外的變量事先記錄下后面的 node,設(shè)為 nxt,這樣才不至于走丟~

        Step1.

        翻轉(zhuǎn)箭頭:把 1 的 next 指針指向 NULL;

        這樣子,同時我們也明確了,prev 的初始化應(yīng)該是 NULL.

        然后把這仨變量都移動到下一個位置:

        Step2.

        翻轉(zhuǎn)箭頭:把 2 的 next 指針指向 1,

        然后三人行:

        Step3.

        翻轉(zhuǎn)箭頭:把 3 的 next 指針指向 2,

        再齊步走:

        Step4.

        再把 4 的反過來:

        再往后走:

        Step5.

        再把 5 的 next 反過來:

        但是因為我們的 while 循環(huán)包含了

        「翻轉(zhuǎn)箭頭」+「三人行」

        兩個步驟,所以還需要走完最后一個三人行,變成:

        很多同學(xué)搞不清楚這個 while 循環(huán)的結(jié)束條件,其實很簡單,你就走個例子畫畫圖嘛!

        那結(jié)束條件就是 curr = null 的時候,
        最后返回的是 prev.

        好了,看代碼吧:

        class?Solution?{
        ????public?ListNode?reverseList(ListNode?head)?{
        ????????ListNode?prev?=?null;
        ????????ListNode?curr?=?head;

        ????????while(curr?!=?null)?{
        ????????????ListNode?nxt?=?curr.next;
        ????????????curr.next?=?prev;?//?翻轉(zhuǎn)箭頭
        ????????????prev?=?curr;?//三人行
        ????????????curr?=?nxt;?//三人行
        ????????}

        ????????return?prev;
        ????}
        }

        時間復(fù)雜度

        這里的時間復(fù)雜度很明顯了,就是過了一遍這個鏈表,所以是 O(n).

        空間復(fù)雜度

        空間是 O(1).


        來個直擊靈魂的三連吧!

        瀏覽 70
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产老熟女高潮毛片A片仙踪林 | 纲手被扒开腿做同人免费 | 成人免费看片视频 | 男女交性全过程无遮视频 | 天天草天天撸 | 在线手机av | 色五月丁香欧美综合 | 肏屄毛片 | 老女人一级特黄A片免费 | 国产精品偷窥熟女 |