博客 / 詳情

返回

衝擊大廠算法面試=>鏈表專題【鏈表刪除】

本文學習目標或者鞏固的知識點

  • 學習如何刪除鏈表中的某個節點

    • 如何刪除val=k的節點
    • 如何刪除倒數第n個節點
  • 學習如何刪除鏈表中的某些節點

    • 涉及頭節點問題如何解決

提前説明:算法題目來自力扣、牛客等等途徑

🟢表示簡單
🟡表示中等
🔴表示困難
🤮表示噁心

237. 刪除鏈表中的節點🟡🟢

有一個單鏈表的 head,我們想刪除它其中的一個節點 node。

給你一個需要刪除的節點 node 。你將 無法訪問 第一個節點  head。

鏈表的所有值都是 唯一的,並且保證給定的節點 node 不是鏈表中的最後一個節點。

刪除給定的節點。注意,刪除節點並不是指從內存中刪除它。這裏的意思是:

  • 給定節點的值不應該存在於鏈表中。
  • 鏈表中的節點數應該減少 1。
  • node 前面的所有值順序相同。
  • node 後面的所有值順序相同。

示例 1:
image

輸入:head = [4,5,1,9], node = 5
輸出:[4,1,9]
解釋:指定鏈表中值為 5 的第二個節點,那麼在調用了你的函數之後,該鏈表應變為 4 -> 1 -> 9

通過題目可知

  1. 我們想刪除它其中的一個節點 node,且入參就是node(我們知道node)
  2. 無法訪問 第一個節點  head
  3. 鏈表的所有值都是唯一的
  4. 節點 node 不是鏈表中的最後一個節點(我們可以拿到node.next)

    題解

超級簡單,不多説

class Solution {
    public void deleteNode(ListNode node) {
        ListNode nextNode = node.next;
        node.val = nextNode.val;
        node.next = nextNode.next;
    }
}

圖解

image

83. 刪除排序鏈表中的重複元素🟢

給定一個已排序的鏈表的頭 head , 刪除所有重複的元素,使每個元素只出現一次 。返回 已排序的鏈表 。

示例 1:
image

輸入:head = [1,1,2]
輸出:[1,2]

通過題目可知

  1. 已排序的鏈表(重複的節點肯定相鄰)
  2. 如果有重複元素,使每個元素只出現一次即可(不用考慮頭節點問題)

    題解

public ListNode deleteDuplicates(ListNode head) {
        ListNode cur = head;
        
        while(cur!=null && cur.next!=null){
            //剔除重複元素 直到不符合
            while(cur!=null && cur.next!=null && cur.val == cur.next.val){
                cur.next = cur.next.next;
            }
            //下一個
            cur = cur.next;
        }
        return head;
    }

圖解

  • cur.val == cur.next.val  即 1=1的時候進入內循環
  • cur.next = cur.next.next; cur後移
  • cur = cur.next; 當cur.val != cur.next.val的時候執行cur後移
    image

82. 刪除排序鏈表中的重複元素 II🟡

給定一個已排序的鏈表的頭 head , 刪除原始鏈表中所有重複數字的節點,只留下不同的數字 。返回 已排序的鏈表 。

示例 1:
image

輸入:head = [1,2,3,3,4,4,5]
輸出:[1,2,5]

通過題目可知

  1. 已排序的鏈表(重複的節點肯定相鄰)
  2. 如果有重複元素,刪除所有重複的元素(需要考慮頭節點問題)

    題解

public ListNode deleteDuplicates(ListNode head) {
    ListNode preHead = new ListNode(-1);
    preHead.next = head;

    ListNode cur = preHead;

    while(cur.next!=null && cur.next.next!=null){
        ListNode nextNode = cur.next;
        ListNode nextNextNode = cur.next.next;
        //不相等
        if(nextNode.val != nextNextNode.val){
            cur = cur.next;
            continue;
        }
        //相等
        while(nextNextNode!= null && nextNode.val == nextNextNode.val){
            nextNextNode = nextNextNode.next;
        }
        cur.next = nextNextNode;
    }
    return preHead.next;
}

圖示

image

19. 刪除鏈表的倒數第 N 個結點🟡

給你一個鏈表,刪除鏈表的倒數第 n 個結點,並且返回鏈表的頭結點。

示例 1:
image

輸入:head = [1,2,3,4,5], n = 2
輸出:[1,2,3,5]

通過題目可知

  1. 我們需要刪除鏈表的倒數第n 個結點(如何尋找這個結點?快慢指針)
  2. 返回鏈表頭結點(沒特殊説明,説明可能刪除頭節點,需要考慮頭節點問題)

    題解

當涉及快慢指針的問題最好打點關鍵的日誌,方法跟蹤問題。

此題為經典的快慢指針問題。

快指針先走N步,然後快慢指針一起走,直到快指針走完鏈表為null。一般慢指針就是要刪除的節點。找到刪除的節點或者要刪除的前一個節點的話就容易多了。

public ListNode removeNthFromEnd(ListNode head, int n) {
    //由於可能刪除頭節點 所以設置虛擬節點preHead
    ListNode preHead = new ListNode(-1);
    preHead.next = head;

    //設置快指針 從preHead開始
    ListNode fast = preHead;
    //先走N+1步
    for(int i=0; i<=n; i++){
        fast = fast.next;
    }
    
    //【調試】
    System.out.println("fast="+(fast==null?"null":fast.val));

    //快慢指針同步走
    ListNode slow = preHead;
    while(fast != null){
        slow = slow.next;
        fast = fast.next;
    }

    //【調試】
    System.out.println("slow="+(slow==null?"null":slow.val));

    //跳過要刪除的點
    slow.next = slow.next.next;

    return preHead.next;
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.