【LeetCode題解】21_合併兩個有序鏈表

目錄

21_合併兩個有序鏈表

描述

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。

示例:

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

解法一:迭代

思路

因爲兩個鏈表都是有序鏈表(遞增),因此可以很容易地找出兩個鏈表中的最小元素,即比較兩個鏈表表頭的元素,時間複雜度是 \(O(1)\) 的。我們可以利用兩個指針——指向兩個鏈表的最小節點,每次比較兩個指針所指向節點的值,將值比較小的節點加到新的鏈表中,然後更新指針,如此循環往復直到到達一個鏈表的尾部。最後,還需要將另一個鏈表的剩餘部分(如果存在的話)添加到新的鏈表的尾部。

Java 實現

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(0);
        ListNode lastNode = dummyHead;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                lastNode.next = l1;
                l1 = l1.next;
            } else {
                lastNode.next = l2;
                l2 = l2.next;
            }
            
            lastNode = lastNode.next;
        }
        lastNode.next = l1 != null ? l1 : l2;
        return dummyHead.next;
    }
}
// Runtime: 9 ms
// Your runtime beats 86.44 % of java submissions.

複雜度分析:

  • 時間複雜度:\(O(m+n)\),其中,\(m\) 爲鏈表 1 的節點數,\(n\) 爲鏈表 2 的節點數,算法需要遍歷兩個鏈表的所有元素
  • 空間複雜度:\(O(1)\),只需要保存兩個引用

Python 實現

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        dummy_head = last_node = ListNode(0)
        while l1 and l2:
            if l1.val < l2.val:
                last_node.next = l1
                l1 = l1.next
            else:
                last_node.next = l2
                l2 = l2.next
            
            last_node = last_node.next
        last_node.next = l1 or l2
        return dummy_head.next
# Runtime: 44 ms
# Your runtime beats 99.24 % of python3 submissions.

複雜度分析同上。

解法二:遞歸

思路

遞歸的思路和迭代的思路是相同的,都是每次比較兩個鏈表的最小節點,然後對值更小的節點進行操作。不同的是,迭代是從值比較小的節點開始組建新的鏈表,而遞歸則是從值比較大的節點開始組建新的鏈表——遞歸到其中一個鏈表的尾部纔開始組建新的鏈表。

Java 實現

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) {
            return l1 != null ? l1 : l2;
        }
        
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}
// Runtime: 8 ms
// Your runtime beats 99.96 % of java submissions.

複雜度分析:

  • 時間複雜度:\(O(m+n)\),其中,\(m\) 爲鏈表 1 的節點數,\(n\) 爲鏈表 2 的節點數,算法需要遍歷兩個鏈表的所有元素
  • 空間複雜度:\(O(m+n)\),額外的空間是由於遞歸調用佔用系統棧的空間,遞歸的深度最多爲 \(m+n\)

Python 實現

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        if not l1 or not l2:
            return l1 or l2
        
        if l1.val < l2.val:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2

複雜度分析同上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章