前言
以專題的形式更新刷題貼,歡迎跟我一起學習刷題,相信我,你的堅持,絕對會有意想不到的收穫。每道題會提供簡單的解答,如果你有更優雅的做法,歡迎提供指點,謝謝
【題目描述】
給定連結串列的頭節點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;
}
最後推廣下我的公眾號:苦逼的碼農,文章都會首發於我的公眾號,期待各路英雄的關注交流。