力扣--連結串列演算法

☆寧發表於2020-10-24

刪除中間點

內容

實現一種演算法,刪除單向連結串列中間的某個節點(即不是第一個或最後一個節點),假定你只能訪問該節點。

示例

輸入:單向連結串列a->b->c->d->e->f中的節點c
結果:不返回任何資料,但該連結串列變為a->b->d->e->f

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val; //將下一節點的值賦給當前節點
        node.next = node.next.next; //當前節點的下一個節點為下下節點,刪除當前節點
    }
}

複雜度

時間複雜度:O(1)。
空間複雜度:O(1)。

二進位制連結串列轉整數

內容

給你一個單連結串列的引用結點 head。連結串列中每個結點的值不是 0 就是 1。已知此連結串列是一個整數數字的二進位制表示形式。請你返回該連結串列所表示數字的 十進位制值 。

示例

輸入:head = [1,0,1]
輸出:5
解釋:二進位制數 (101) 轉化為十進位制數 (5)

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int getDecimalValue(ListNode head) {
        ListNode cur = head;  
        int ans = 0;
        while(cur != null){
            //連結串列只有0/1
            ans = ans * 2 + cur.val;
            cur = cur.next;
        }
        return ans;
    }
}

複雜度

時間複雜度:O(N),其中N是連結串列中的節點個數。
空間複雜度:O(1)。

返回倒數第K個節點

內容

實現一種演算法,找出單向連結串列中倒數第 k 個節點。返回該節點的值。

示例

輸入: 1->2->3->4->5 和 k = 2
輸出: 4

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int kthToLast(ListNode head, int k) {
        if(k <= 0 || head == null){
            return 0;
        }
        ListNode fast = head;
        ListNode slow = head;
        //讓快指標先快走K-1步
        while(k - 1 > 0){ 
            fast = fast.next;
            k--;
        }
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next;
        }
        return slow.val;
    }
}

複雜度

時間複雜度 O(N) :N為連結串列長度。
空間複雜度 O(1)。

從尾到頭列印連結串列

內容

輸入一個連結串列的頭節點,從尾到頭反過來返回每個節點的值(用陣列返回)。

示例

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

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
    //使用棧,先進後出原則
        Stack<ListNode> stack = new Stack<ListNode>();
        ListNode node = head;
        while(node != null){
            stack.push(node);
            node = node.next;
        }
        int size = stack.size();
        int[] print = new int[size];
        for(int i = 0;i < size;i++){
            print[i] = stack.pop().val;
        }
        return print;
    }
}

複雜度

時間複雜度:O(n)正向遍歷一遍連結串列,然後從棧彈出全部節點,等於又反向遍歷一遍連結串列。
空間複雜度:O(n)額外使用一個棧儲存連結串列中的每個節點。

連結串列的中間結點

內容

給定一個頭結點為 head 的非空單連結串列,返回連結串列的中間結點。

如果有兩個中間結點,則返回第二個中間結點。

示例

輸入:[1,2,3,4,5]
輸出:此列表中的結點 3 (序列化形式:[3,4,5])
返回的結點值為 3 。 (測評系統對該結點序列化表述是 [3,4,5])。
注意,我們返回了一個 ListNode 型別的物件 ans,這樣:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            
        }
        return slow;
    }
}

複雜度

時間複雜度:O(N)O(N),其中 NN 是給定連結串列的結點數目。
空間複雜度:O(1)O(1),只需要常數空間存放 slow 和 fast 兩個指標。

移除重複節點

內容

編寫程式碼,移除未排序連結串列中的重複節點。保留最開始出現的節點。

示例

輸入:[1, 2, 3, 3, 2, 1]
輸出:[1, 2, 3]

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeDuplicateNodes(ListNode head) {
        if(head == null){
            return head;
        }
        //HashSet特點無序不可重複
        Set<Integer> occurred = new HashSet<Integer>();
        //先將頭節點的值加進雜湊表中
        occurred.add(head.val);
        ListNode pos = head;
        while(pos.next != null){
            ListNode cur = pos.next;
            if(occurred.add(cur.val)){
                pos = pos.next;
            }else{
                pos.next = pos.next.next;
            }
        }
        pos.next = null;
        return head;
    }
}

複雜度

時間複雜度:O(N),其中 N 是給定連結串列中節點的數目。
空間複雜度:O(N)。在最壞情況下,給定連結串列中每個節點都不相同,雜湊表中需要儲存所有的 N 個值。

反轉連結串列

內容

反轉一個單連結串列。

示例

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

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while(curr != null){
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }
}

複雜度

時間複雜度:O(n),假設 n 是列表的長度,時間複雜度是 O(n)。
空間複雜度:O(1)。

合併兩個有序連結串列

內容

將兩個升序連結串列合併為一個新的 升序 連結串列並返回。新連結串列是通過拼接給定的兩個連結串列的所有節點組成的。

示例

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

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode prehead = new ListNode(-1);
        ListNode prev = prehead;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                prev.next = l1;
                l1 = l1.next;
            }else{
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }
        //合併後l1和l2最多隻有一個還未被合併完,我們直接將連結串列末尾指向未合併完的連結串列即可
        prev.next = l1 == null ? l2 : l1;
        return prehead.next;
    }
}

複雜度

時間複雜度:O(n + m)O(n+m) ,其中 nn 和 mm 分別為兩個連結串列的長度。因為每次迴圈迭代中,l1 和 l2 只有一個元素會被放進合併連結串列中, 因此 while 迴圈的次數不會超過兩個連結串列的長度之和。所有其他操作的時間複雜度都是常數級別的,因此總的時間複雜度為 O(n+m)O(n+m)。

空間複雜度:O(1)O(1) 。我們只需要常數的空間存放若干變數。

連結串列相交

內容

給定兩個(單向)連結串列,判定它們是否相交併返回交點。請注意相交的定義基於節點的引用,而不是基於節點的值。換句話說,如果一個連結串列的第k個節點與另一個連結串列的第j個節點是同一節點(引用完全相同),則這兩個連結串列相交。

示例

輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Reference of the node with value = 8
輸入解釋:相交節點的值為 8 (注意,如果兩個列表相交則不能為 0)。從各自的表頭開始算起,連結串列 A 為 [4,1,8,4,5],連結串列 B 為 [5,0,1,8,4,5]。在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode t1 = headA;
        ListNode t2 = headB;
        while(t1 != t2){
            t1 = t1 != null ? t1.next : headB;
            t2 = t2 != null ? t2.next : headA;
        }
        return t2;
    }
}

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

內容

示例

程式碼

複雜度

相關文章