單鏈表刪除相關算法總結(5種題型)

目錄


本文介紹單鏈表刪除相關的常見算法。

  1. 移除鏈表元素(力扣:203)
  2. 刪除鏈表中的節點(力扣:237)
  3. 刪除鏈表的倒數第N個節點(力扣:19)
  4. 刪除排序鏈表中的重複元素(力扣:83)
  5. 刪除排序鏈表中的重複元素 II(力扣:82)

算法實現


鏈表節點:

    public class ListNode{
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
        }
    }

1. 移除鏈表元素

題目

刪除鏈表中等於給定值 val 的所有節點。

分析
  1. 刪除一個節點,我們首先要找到目標節點。
  2. 然後,目標節點的上一個節點的next,指向目標節點的next節點,即可完成刪除。
  3. 然而head節點沒有“上一個節點”,這時,我們需要新建一個啞節點,然後讓它作爲head節點的上一個節點。
啞節點

啞節點(dummy node)是初始值爲NULL的節點,它可以起到避免處理頭節點爲空的邊界問題的作用,減少代碼執行異常的可能性。

啞節點的使用可以對代碼起到簡化作用,在刪除節點,或者進行有序插入時,帶有頭部啞節點的鏈表可以簡化代碼的邏輯,我們的代碼可以不用考慮第一個節點的特殊情況。

代碼實現
    /**
     * 刪除鏈表中等於val的所有節點 leetcode203
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements(ListNode head, int val){
        ListNode pre = new ListNode(-1);
        pre.next = head;
        ListNode cur = pre;
        while (cur.next != null){
            if (cur.next.val == val){
                cur.next = cur.next.next;
            }else {
                cur = cur.next;
            }
        }
        return pre.next;
    }

2. 刪除鏈表中的節點

題目

請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點,你將只被給定要求被刪除的節點。

說明:

鏈表至少包含兩個節點。
鏈表中所有節點的值都是唯一的。
給定的節點爲非末尾節點並且一定是鏈表中的一個有效節點。
不要從你的函數中返回任何結果。

分析

這個題目輸入參數只有一個,是將要刪除的節點,所以題目可以理解爲”刪除指定的節點“。

刪除當前節點,需要找到上一個節點,然後讓上一個節點的next指向,當前節點的next節點即可。但是這是一個單鏈表,我們通過當前節點無法找到它的上一個節點。

所以,我們需要換個思路,將當前節點改爲next節點,然後刪除next節點也就變相的實現了刪除當前節點了。

代碼實現
    /**
     * 刪除當前節點 leetcode 19
     * @param head
     */
    public void deleteNode(ListNode head) {
        ListNode next = head.next;
        head.val = next.val;
        head.next = next.next;
    }

3. 刪除鏈表的倒數第N個節點

題目

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

分析

刪除鏈表的倒數第N個節點,最簡單的方法就是遍歷鏈表,找到鏈表的長度,然後再找找倒數N個節點就非常簡答了。但是這樣會經過2次遍歷。

我們換個思路:

  1. 使用快慢指針(雙指針),讓快指針先走N-1個節點,然後快慢指針一起走,當快指針指向最後一個節點時,慢指針指向了倒數第N個節點。
  2. 同時,我們可以使用啞節點來處理頭節點的邊界問題。
代碼實現
    /**
     * 刪除鏈表的倒數第N個節點  leetcode 19
     * @param head
     * @param n
     * @return
     */
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode quick = dummy;
        ListNode slow = dummy;
        for (int i = 0; i < n + 1; i++) {
            quick = quick.next;
        }
        while (quick != null) {
            quick = quick.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }

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

題目

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

分析

題目中的單鏈表是已排序的列表,所以,從鏈表頭開始,依次對比節點值,如果相等,則刪除即可。

代碼實現
    /**
     * 83. 刪除排序鏈表中的重複元素
     * @param head
     * @return
     */
    public ListNode deleteDuplicates(ListNode head) {
        ListNode cur = head;
        while (cur != null && cur.next != null){
            if (cur.val == cur.next.val){
                cur.next = cur.next.next;
            }else {
                cur = cur.next;
            }
        }
        return head;
    }

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

題目

給定一個排序鏈表,刪除所有含有重複數字的節點,只保留原始鏈表中沒有重複出現的數字。

示例:

輸入: 1->2->3->3->4->4->5
輸出: 1->2->5

分析

該題和上一題的區別是:要刪除重複數字的所有節點。

思路1:可以使用上一題的思路,遍歷整個鏈表,當節點中的值出現重複時,則刪除重複的節點,例如節點3重複,則刪除第一個之後所有重複的節點,最後刪除當前節點即可。
思路2:遍歷鏈表時,使用2個指針,第一個指針pre指向無重複節點的最右端,第二個指針cur指向當前節點,當前節點與後面節點值相等時,當前節點後移一位,直到找到不相等的值爲止,這時讓pre的next指向cur的next,就會把所有重複元素都刪除掉了。

代碼實現1
    /**
     * 82. 刪除排序鏈表中的重複元素 II
     *
     * @param head
     * @return
     */
    public ListNode deleteDuplicates2(ListNode head) {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode cur = head, pre = dummy;
        boolean isDel = false;
        while (cur != null && cur.next != null) {
            if (cur.val == cur.next.val) {
                cur.next = cur.next.next;
                isDel = true;
            } else {
                if (isDel) {
                    pre.next = cur.next;
                    cur = pre.next;
                    isDel = false;
                } else {
                    pre = cur;
                    cur = cur.next;
                }
            }
        }
        if (isDel) {
            pre.next = cur.next;
        }
        return dummy.next;
    }
代碼實現2
    /**
     * 82. 刪除排序鏈表中的重複元素 II
     *
     * @param head
     * @return
     */
    public ListNode deleteDuplicates1(ListNode head) {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode cur = dummy.next, pre = dummy;
        while (cur != null && cur.next != null) {
            if (cur.val == cur.next.val) {
                while (cur != null && cur.next != null && cur.val == cur.next.val) {
                    cur = cur.next;
                }
                pre.next = cur.next;
                cur = pre.next;
            } else {
                pre = pre.next;
                cur = cur.next;
            }
        }
        return dummy.next;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章