1. 程式人生 > 其它 >【LeetCode】連結串列問題:虛擬頭節點

【LeetCode】連結串列問題:虛擬頭節點

技術標籤:# LeetCodeleetcode演算法

虛擬頭節點

  • 對於有刪除問題,一定要設定虛擬頭節點

203. 移除連結串列元素

難度簡單521收藏分享切換為英文接收動態反饋

刪除連結串列中等於給定值 *val* 的所有節點。

示例:

輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

題解

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode firstNode =
new ListNode(); firstNode.next = head; ListNode pre = firstNode; ListNode node = firstNode.next; while(node != null){ if(node .val == val){ pre.next = node = node.next; }else { pre = node ; node =
node.next; } } return firstNode.next; } }

82. 刪除排序連結串列中的重複元素 II

難度中等442收藏分享切換為英文接收動態反饋

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

示例 1:

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

示例 2:

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

題解

class Solution
{ public ListNode deleteDuplicates(ListNode head) { ListNode resHead = null; ListNode resTail = null; ListNode node = head; int beforeData = Integer.MAX_VALUE; boolean canUseBeforeData = true; while(node != null){ if(node == head){ beforeData = node.val; node = node.next; continue; } if(beforeData == node.val){ canUseBeforeData = false; node = node.next; continue; } if(canUseBeforeData){ if(resHead == null){ resHead = resTail = new ListNode(beforeData); }else { resTail.next = new ListNode(beforeData); resTail = resTail.next; } } beforeData = node.val; canUseBeforeData = true; node = node.next; } if(canUseBeforeData && head != null){ if(resHead == null){ resHead = new ListNode(beforeData); }else { resTail.next = new ListNode(beforeData); } } return resHead; } }

24. 兩兩交換連結串列中的節點

難度中等799收藏分享切換為英文接收動態反饋

給定一個連結串列,兩兩交換其中相鄰的節點,並返回交換後的連結串列。

你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。

示例 1:

在這裡插入圖片描述

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

示例 2:

輸入:head = []
輸出:[]

示例 3:

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

題解

  • 對於迴圈中(即遞推中)操作較複雜或者冗餘,考慮換成遞迴
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode firstNode = new ListNode();
        firstNode.next = head;

        func(firstNode);
        return firstNode.next;
    }

    void func(ListNode head){
        ListNode next = head.next;
        ListNode next2 = null;

        if(next != null){
            next2 = next.next;
        }
        if(next == null || next2 == null){
            return;
        }

        ListNode append = next2.next;
        head.next = next2;
        next2.next = next;
        next.next = append;

        func(next);
    }
}

25. K 個一組翻轉連結串列

難度困難881收藏分享切換為英文接收動態反饋

給你一個連結串列,每 k 個節點一組進行翻轉,請你返回翻轉後的連結串列。

k 是一個正整數,它的值小於或等於連結串列的長度。

如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。

示例:

給你這個連結串列:1->2->3->4->5

k = 2 時,應當返回: 2->1->4->3->5

k = 3 時,應當返回: 3->2->1->4->5

說明:

  • 你的演算法只能使用常數的額外空間。
  • 你不能只是單純的改變節點內部的值,而是需要實際進行節點交換

題解

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode firstNode = new ListNode();
        firstNode.next = head;

        func(firstNode ,k);
        return firstNode.next;
    }

    void func(ListNode head , int k){
        ListNode node = head.next;

        int sum = 0;
        while(node != null && sum != k){
            sum ++;
            node = node.next;
        }

        if(sum != k){
            return;
        }

        ListNode pre = null;
        ListNode cur = head.next;
        ListNode after = null;
        for(int i = 0 ; i < k ; i ++){
            after = cur.next;
            cur.next = pre;
            
            pre = cur;
            cur = after;
        }

        ListNode kLast = head.next ;
        kLast.next = cur;
        head.next = pre;

        func(kLast , k);
    }
}

147. 對連結串列進行插入排序

難度中等346收藏分享切換為英文接收動態反饋

對連結串列進行插入排序。

插入排序的動畫演示如上。從第一個元素開始,該連結串列可以被認為已經部分排序(用黑色表示)。
每次迭代時,從輸入資料中移除一個元素(用紅色表示),並原地將其插入到已排好序的連結串列中。

插入排序演算法:

  1. 插入排序是迭代的,每次只移動一個元素,直到所有元素可以形成一個有序的輸出列表。
  2. 每次迭代中,插入排序只從輸入資料中移除一個待排序的元素,找到它在序列中適當的位置,並將其插入。
  3. 重複直到所有輸入資料插入完為止。

示例 1:

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

示例 2:

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

題解

class Solution {
    public ListNode insertionSortList(ListNode head) {
        if(head == null){
            return null;
        }
        
        ListNode sortArea = head;
        while(sortArea.next != null){
            sortArea = sortArea.next;
        }

        ListNode sortHead = new ListNode();
        sortHead.next = sortArea;
 
        ListNode node = head;
        while(node != sortArea){
            ListNode preI = sortHead;
            ListNode i = sortHead.next;
            while(i != null && node.val > i.val){
                preI = i;
                i = i.next;
            }

            
            ListNode next = node.next;
            preI.next = node;
            node.next = i;

            node = next;
        }

        return sortHead.next;
    }
}

19. 刪除連結串列的倒數第 N 個結點

難度中等1199收藏分享切換為英文接收動態反饋

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

**進階:**你能嘗試使用一趟掃描實現嗎?

示例 1:

在這裡插入圖片描述

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

示例 2:

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

示例 3:

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

題解

遍歷

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int sum = 0;
        ListNode node = head;

        while(node !=  null){
            node = node.next;
            sum ++;
        }

        int idx = sum - n + 1;
        int i = 1;

        ListNode firstNode = new ListNode();
        firstNode.next = head;

        ListNode pre = firstNode;
        node = firstNode.next;
        
        while(idx != i){
            i ++;
            pre = node;
            node = node.next;
        }

        pre.next = node.next;
        return firstNode.next;
    }
}

回溯

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode firstNode = new ListNode();
        firstNode.next = head;

        func(firstNode ,n);    
        return firstNode.next;
    }

    int func(ListNode head , int n){
        if(head.next == null){
            return 1;
        }

        int res = func(head.next ,n);
        if(res == n ){
            head.next = head.next.next;
        }

        return res + 1;
    }
    
}