劍指Offer題目13:在O(1)時間刪除鏈表結點(Java)

面試題13:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。node

Basic

只要涉及到鏈表的增、刪操做,就須要考慮如下三種場景:面試

場景1:(特殊場景)只有一個頭結點,對頭結點進行操做

場景2:(普通場景)有多個結點,操做中間節點

場景3:(特殊場景)對尾節點進行操做
複製代碼

解題思路

首先考慮普通場景,再考慮特殊場景。bash

普通場景:

因爲要求的時間複雜度爲O(1),若是採用常規思惟,從頭結點遍歷到目標節點,則時間複雜度爲O(n),沒法知足要求。

刪除某節點,意味着將某個目標值 date 對應的節點從鏈表中抹去,能夠是直接刪除,也能夠是用新的值來覆蓋舊的值,而後用
新的後序節點覆蓋舊的後序節點。

若是採用直接刪除的方式,須要從頭結點遍歷起,時間複雜度爲 O(n), 沒法知足 O(1) 的要求。

所以須要採起覆蓋抹去目標節點的方式來達到刪除節點的目的。

解決方案:

Step 1: 將目標節點的 next 節點的值賦給目標節點

Step 2:將目標節點的 next 的後序節點賦給目標節點的 next

此時,目標節點被其後序節點 next 徹底覆蓋,同時目標節點原來的後序節點 next 沒指向它,即被刪掉。

實現刪除目標節點的目的,時間複雜度爲 O(1)。

特殊場景:

1. 刪除頭節點

直接刪除頭結點,時間複雜度 O(1)。

2. 刪除尾節點

須要從頭結點開始遍歷到尾部,對於 n-1 箇中間節點,時間複雜度爲 O(n)。

總的平均時間複雜度:

[(n-1) * O(1) + O(n)] / n 

結果仍是 O(1)

複製代碼

代碼實現

public static void deleteNodeInO1(Node head, Node target){
    if (head == null || target == null) {
        return;
    }
    //若是刪除的是頭結點,無論當前鏈表是否只有一個頭結點,都直接賦 head.next,只有一個頭結點時,
    //head.next 爲 null
    if (head == target) {
        head = head.next;
    } else if (target.next != null) { //普通場景:覆蓋抹除法
        Node nextNode = target.next;
        target.data = nextNode.data;
        target.next = nextNode.next;
    } else { //刪除尾節點,只能從頭遍歷到導數第二個節點,再刪除最後節點
        Node node = head;
        //注意,此處只能遍歷到尾節點以前的一個節點,即倒數第二個節點,由於刪除尾節點須要其前一個節點做爲操做入口
        while (node.next != target) {
            node = node.next;
        }
        node.next = null; //此處 node.next 就是最後一個節點,將最後一個節點置空,就至關於刪除最後節點
    }
}
複製代碼

總結

刪除節點也可使用 覆蓋抹除法(自創詞彙方便記憶),時間複雜度爲 O(1)函數

相關文章
相關標籤/搜索