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.

相关推荐
我命由我123452 小时前
Java 开发 - 粘包处理器 - 基于消息头 + 消息体(魔数验证、长度验证)
java·网络·后端·网络协议·java-ee·intellij-idea·intellij idea
2301_800399722 小时前
stm32 printf重定向到USART
java·stm32·算法
bagadesu2 小时前
15.<Spring Boot 日志>
java·后端
laplace01232 小时前
Maven
java·maven
wdfk_prog2 小时前
Xshell终端连接Ubuntu/Debian无颜色的解决方案
java·ubuntu·debian
艾迪的技术之路2 小时前
linux上gitlab runner部署文档
java·github
凌波粒2 小时前
SpringMVC基础教程(3)--SSM框架整合
java·sql·spring·intellij-idea·mybatis
2021_fc3 小时前
分布式应用可观测全链路追踪技术
java
数据的世界013 小时前
JAVA和C#的语法对比
java·windows·c#