【連結串列問題】打卡3:刪除單連結串列的中間節點

帥地發表於2019-02-24

前言

以專題的形式更新刷題貼,歡迎跟我一起學習刷題,相信我,你的堅持,絕對會有意想不到的收穫。每道題會提供簡單的解答,如果你有更優雅的做法,歡迎提供指點,謝謝

【題目描述】

給定連結串列的頭節點head,實現刪除連結串列的中間節點的函式。

  例如:

  步刪除任何節點;

  1->2,刪除節點1;

  1->2->3,刪除節點2;

  1->2->3->4,刪除節點2;

  1->2->3->4-5,刪除節點3;

【要求】

如果連結串列的長度為 N, 時間複雜度達到 O(N), 額外空間複雜度達到 O(1)

【難度】

士:★☆☆☆

【解答】

這道題要求刪除中間節點,我們可以採用雙指標的方法來做,就是用一個快指標和一個慢指標,快指標每次前進兩個節點,而慢指標每次前進一個節點。當快指標遍歷完節點時,慢指標剛好就在中間節點了。之前寫過一篇一些演算法的常用技巧也有所過指標使用的一些技巧。

不過在做的時候,最好是先把一些特殊情況先處理好,例如刪除的可能是第一個節點,也有可能不用刪除節點(只有一個節點時就不用刪除了。

程式碼如下

    public static Node removeMidNode(Node head) {
        if(head == null || head.next == null)
            return head;
        if (head.next.next == null) {
            return head.next;
        }
        Node fast = head.next.next;//快指標
        Node slow = head;//慢指標

        //slow最終指向中間節點的前驅
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        //進行刪除
        slow.next = slow.next.next;
        return head;
    }

上次拿到刪除倒數第 K 個節點的題其實也是可以使用雙指標的,但個人認為,那道題使用雙指標的方法並沒有我上次那個做法優雅,而這次刪除中間節點,則用雙指標比較優雅。至於原因,可以自己打下程式碼看看

問題擴充

題目:刪除連結串列中 a / b 處的節點

【題目描述】

  給定連結串列的頭節點 head、整數 a 和 b,實現刪除位於 a/b 處節點的函式。

  例如:

  連結串列:1->2->3->4->5,假設 a/b 的值為 r。

  如果 r = 0,不刪除任何節點;

  如果 r 在區間 (0,1/5] 上,刪除節點 1;

  如果 r 在區間 (1/5,2/5] 上,刪除節點 2;

  如果 r 在區間 (2/5,3/5] 上,刪除節點 3;

  如果 r 在區間 (3/5,4/5] 上,刪除節點 4;

  如果 r 在區間 (4/5,1] 上,刪除節點 5;

  如果 r 大於 1,不刪除任何節點。

【要求】

如果連結串列的長度為 N, 時間複雜度達到 O(N), 額外空間複雜度達到 O(1)

【難度】

士:★☆☆☆

【解答】

可以自己動手做一下或者想一下,如果想要獲取答案,可以在公眾號回覆 解答1 獲取程式碼。

    //這道題可以轉換為刪除第 K = (a * n / b)個節點。其中n表示連結串列節點
    //的個數,但由於(a * n / b)有可能出現小數,所以我們取 K的上限。
    //所謂上限就是大於等於K的最小整數。
    public static Node removeByRatio(Node head, int a, int b) {
        if(a < 1 || a > b)
            return head;
        int n = 0;
        Node cur = head;
        //統計一共有多少個節點
        while (cur != null)
            n++;
        //問題轉換為刪除第K個節點,取(a * n / b)的整數上限
        int K =  (int)Math.ceil((double)(a * n) / (double)b);
        if(K == 1)
            return head.next;
        if (K > 1) {
            cur = head;
            //定位到第K個節點的前驅
            while (--K != 1) {
                cur = cur.next;
            }
            cur.next = cur.next.next;
        }
        return head;
    }

最後推廣下我的公眾號:苦逼的碼農,文章都會首發於我的公眾號,期待各路英雄的關注交流。

相關文章