LeetCode 21: Merge Two Sorted Lists

LeetCode 21: Merge Two Sorted Lists

    • [1. Problem Link 🔗](#1. Problem Link 🔗)
    • [2. Solution Overview 🧭](#2. Solution Overview 🧭)
    • [3. Solution 1: Iterative with Dummy Node (Recommended)](#3. Solution 1: Iterative with Dummy Node (Recommended))
      • [3.1. Algorithm](#3.1. Algorithm)
      • [3.2. Important Points](#3.2. Important Points)
      • [3.3. Java Implementation](#3.3. Java Implementation)
      • [3.4. Time & Space Complexity](#3.4. Time & Space Complexity)
    • [4. Solution 2: Recursive Approach](#4. Solution 2: Recursive Approach)
      • [4.1. Algorithm](#4.1. Algorithm)
      • [4.2. Important Points](#4.2. Important Points)
      • [4.3. Java Implementation](#4.3. Java Implementation)
      • [4.4. Time & Space Complexity](#4.4. Time & Space Complexity)
    • [5. Solution 3: Iterative without Dummy Node](#5. Solution 3: Iterative without Dummy Node)
      • [5.1. Algorithm](#5.1. Algorithm)
      • [5.2. Important Points](#5.2. Important Points)
      • [5.3. Java Implementation](#5.3. Java Implementation)
      • [5.4. Time & Space Complexity](#5.4. Time & Space Complexity)
    • [6. Solution 4: In-place Merge (Modifying Original Lists)](#6. Solution 4: In-place Merge (Modifying Original Lists))
      • [6.1. Algorithm](#6.1. Algorithm)
      • [6.2. Important Points](#6.2. Important Points)
      • [6.3. Java Implementation](#6.3. Java Implementation)
      • [6.4. Time & Space Complexity](#6.4. Time & Space Complexity)
    • [7. Solution 5: Recursive with Tail Optimization](#7. Solution 5: Recursive with Tail Optimization)
      • [7.1. Algorithm](#7.1. Algorithm)
      • [7.2. Important Points](#7.2. Important Points)
      • [7.3. Java Implementation](#7.3. Java Implementation)
      • [7.4. Time & Space Complexity](#7.4. Time & Space Complexity)
    • [8. Solution Comparison 📊](#8. Solution Comparison 📊)
    • [9. Summary 📝](#9. Summary 📝)

LeetCode 21: Merge Two Sorted Lists

2. Solution Overview 🧭

Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.

Example:

复制代码
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]

Constraints:

  • The number of nodes in both lists is in the range [0, 50]
  • -100 <= Node.val <= 100
  • Both lists are sorted in non-decreasing order

Common approaches include:

  • Iterative Approach: Use a dummy node and build the merged list step by step
  • Recursive Approach: Recursively merge the lists by comparing heads
  • In-place Merge: Merge without using extra space by rearranging pointers

3. Solution 1: Iterative with Dummy Node (Recommended)

3.1. Algorithm

  • Create a dummy node to simplify edge cases
  • Use a current pointer to build the new list
  • Compare nodes from both lists and attach the smaller one
  • Handle remaining nodes after one list is exhausted

3.2. Important Points

  • Most intuitive and commonly used approach
  • Handles edge cases gracefully
  • Easy to understand and implement

3.3. Java Implementation

java 复制代码
/**
 * 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 list1, ListNode list2) {
        // Create a dummy node to simplify code
        ListNode dummy = new ListNode(-1);
        ListNode current = dummy;
        
        // Traverse both lists
        while (list1 != null && list2 != null) {
            if (list1.val <= list2.val) {
                current.next = list1;
                list1 = list1.next;
            } else {
                current.next = list2;
                list2 = list2.next;
            }
            current = current.next;
        }
        
        // Attach remaining nodes from either list
        if (list1 != null) {
            current.next = list1;
        } else {
            current.next = list2;
        }
        
        return dummy.next;
    }
}

3.4. Time & Space Complexity

  • Time Complexity: O(m + n) where m and n are lengths of the two lists
  • Space Complexity: O(1) - only using a constant amount of extra space

4. Solution 2: Recursive Approach

4.1. Algorithm

  • Compare the heads of both lists
  • Set the smaller head as the current node
  • Recursively merge the remaining lists
  • Base case: when one list is null, return the other list

4.2. Important Points

  • Elegant and concise
  • Uses O(m + n) stack space for recursion
  • Good for understanding recursive thinking

4.3. Java Implementation

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // Base cases
        if (list1 == null) return list2;
        if (list2 == null) return list1;
        
        // Compare and recursively merge
        if (list1.val <= list2.val) {
            list1.next = mergeTwoLists(list1.next, list2);
            return list1;
        } else {
            list2.next = mergeTwoLists(list1, list2.next);
            return list2;
        }
    }
}

4.4. Time & Space Complexity

  • Time Complexity: O(m + n)
  • Space Complexity: O(m + n) - recursion stack

5. Solution 3: Iterative without Dummy Node

5.1. Algorithm

  • Handle the head initialization separately
  • Use a current pointer to build the list
  • Similar to dummy node approach but handles head case explicitly

5.2. Important Points

  • Saves one node of memory
  • More complex edge case handling
  • Good for understanding pointer manipulation

5.3. Java Implementation

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null) return list2;
        if (list2 == null) return list1;
        
        ListNode head, current;
        
        // Initialize head
        if (list1.val <= list2.val) {
            head = list1;
            list1 = list1.next;
        } else {
            head = list2;
            list2 = list2.next;
        }
        current = head;
        
        // Merge the lists
        while (list1 != null && list2 != null) {
            if (list1.val <= list2.val) {
                current.next = list1;
                list1 = list1.next;
            } else {
                current.next = list2;
                list2 = list2.next;
            }
            current = current.next;
        }
        
        // Attach remaining nodes
        if (list1 != null) {
            current.next = list1;
        } else {
            current.next = list2;
        }
        
        return head;
    }
}

5.4. Time & Space Complexity

  • Time Complexity: O(m + n)
  • Space Complexity: O(1)

6. Solution 4: In-place Merge (Modifying Original Lists)

6.1. Algorithm

  • Merge the lists by rearranging pointers without dummy node
  • Choose the smaller head as the main list
  • Insert nodes from the other list into the main list

6.2. Important Points

  • More complex pointer manipulation
  • Modifies the original lists
  • Memory efficient

6.3. Java Implementation

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null) return list2;
        if (list2 == null) return list1;
        
        // Ensure list1 starts with the smaller value
        if (list1.val > list2.val) {
            ListNode temp = list1;
            list1 = list2;
            list2 = temp;
        }
        
        ListNode head = list1;
        
        while (list1 != null && list2 != null) {
            ListNode prev = null;
            
            // Traverse list1 until we find where to insert from list2
            while (list1 != null && list1.val <= list2.val) {
                prev = list1;
                list1 = list1.next;
            }
            
            // Insert list2 node
            prev.next = list2;
            
            // Swap list1 and list2 to continue
            if (list1 != null) {
                ListNode temp = list1;
                list1 = list2;
                list2 = temp;
            }
        }
        
        return head;
    }
}

6.4. Time & Space Complexity

  • Time Complexity: O(m + n)
  • Space Complexity: O(1)

7. Solution 5: Recursive with Tail Optimization

7.1. Algorithm

  • Optimized recursive approach
  • Avoids some stack frames by handling consecutive nodes iteratively
  • Combines recursion with iterative optimization

7.2. Important Points

  • More efficient recursion
  • Reduces stack depth in some cases
  • Still uses O(min(m, n)) stack space

7.3. Java Implementation

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // Base cases
        if (list1 == null) return list2;
        if (list2 == null) return list1;
        
        ListNode head;
        
        if (list1.val <= list2.val) {
            head = list1;
            // Optimize by handling consecutive smaller nodes iteratively
            while (list1.next != null && list1.next.val <= list2.val) {
                list1 = list1.next;
            }
            head.next = mergeTwoLists(list1.next, list2);
        } else {
            head = list2;
            // Optimize by handling consecutive smaller nodes iteratively
            while (list2.next != null && list2.next.val <= list1.val) {
                list2 = list2.next;
            }
            head.next = mergeTwoLists(list1, list2.next);
        }
        
        return head;
    }
}

7.4. Time & Space Complexity

  • Time Complexity: O(m + n)
  • Space Complexity: O(min(m, n)) - optimized recursion stack

8. Solution Comparison 📊

Solution Time Complexity Space Complexity Advantages Disadvantages
Iterative with Dummy O(m+n) O(1) Simple, handles edges well Uses one extra node
Recursive O(m+n) O(m+n) Elegant, concise Stack overflow risk
Iterative without Dummy O(m+n) O(1) No extra node Complex edge handling
In-place Merge O(m+n) O(1) Memory efficient Complex pointer logic
Optimized Recursive O(m+n) O(min(m,n)) Better recursion Still uses stack space

9. Summary 📝

  • Key Insight: Compare nodes from both lists and always choose the smaller one to maintain sorted order
  • Recommended Approach: Solution 1 (Iterative with Dummy Node) is most commonly used in interviews
  • Pattern Recognition: This is a fundamental merge pattern used in many algorithms like merge sort
  • Edge Cases: Handle empty lists and lists of different lengths gracefully

Why Dummy Node is Helpful:

  • Eliminates special case for the head node
  • Simplifies code logic
  • Makes the algorithm more readable and maintainable

The iterative approach with dummy node is generally preferred for its simplicity, efficiency, and readability.

相关推荐
無限進步D1 小时前
Java 运行原理
java·开发语言·入门
難釋懷1 小时前
安装Canal
java
是苏浙1 小时前
JDK17新增特性
java·开发语言
阿里加多5 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood5 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员5 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai
IronMurphy5 小时前
【算法三十九】994. 腐烂的橘子
算法
迷茫的启明星5 小时前
各职业在当前发展阶段,使用AI的舒适区与盲区
大数据·人工智能·职场和发展
zs宝来了6 小时前
AQS详解
java·开发语言·jvm
Ares-Wang6 小时前
算法》》旅行商问题 TSP、7座桥问题 哈密顿回路 深度优先 和 宽度优先
算法·深度优先·宽度优先