LeetCode 第21题:合并两个有序链表

LeetCode 第21题:合并两个有序链表

题目描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

难度

简单

题目链接

https://leetcode.cn/problems/merge-two-sorted-lists/

示例

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

解题思路

方法一:迭代法

使用迭代的方式,逐个比较两个链表的节点值,将较小的节点添加到结果链表中。

关键点:

  1. 使用虚拟头节点(dummy node)简化操作
  2. 同时遍历两个链表,比较节点值
  3. 处理剩余节点
  4. 注意空链表的情况

具体步骤:

  1. 创建虚拟头节点
  2. 使用指针遍历两个链表:
    • 比较当前节点的值
    • 将较小的节点接入结果链表
    • 移动对应链表的指针
  3. 处理剩余节点
  4. 返回虚拟头节点的下一个节点

时间复杂度:O(n + m),其中n和m是两个链表的长度
空间复杂度:O(1)

方法二:递归法

利用递归的特性,将问题分解为更小的子问题。

递归的思路:

  1. 比较两个链表当前节点的值
  2. 选择较小的节点作为当前节点
  3. 递归处理剩余部分
  4. 基线条件是其中一个链表为空

代码实现

C# 实现(迭代法)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution {
    public ListNode MergeTwoLists(ListNode list1, ListNode list2) {
        // 创建虚拟头节点
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
      
        // 同时遍历两个链表
        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;
        }
      
        // 处理剩余节点
        current.next = list1 ?? list2;
      
        return dummy.next;
    }
}

C# 实现(递归法)

public class Solution {
    public ListNode MergeTwoLists(ListNode list1, ListNode list2) {
        // 处理基线条件
        if (list1 == null) return list2;
        if (list2 == null) return list1;
      
        // 比较当前节点,递归处理
        if (list1.val <= list2.val) {
            list1.next = MergeTwoLists(list1.next, list2);
            return list1;
        } else {
            list2.next = MergeTwoLists(list1, list2.next);
            return list2;
        }
    }
}

代码详解

迭代版本:

  1. 虚拟头节点:
    • 使用dummy节点简化边界情况
    • 避免处理头节点的特殊情况
  2. 遍历过程:
    • 比较两个链表当前节点的值
    • 将较小的节点接入结果链表
    • 移动指针
  3. 处理剩余节点:
    • 使用空合并运算符 ?? 简化代码
    • 直接接上剩余的链表

递归版本:

  1. 基线条件:
    • 处理空链表的情况
  2. 递归过程:
    • 比较当前节点的值
    • 递归处理剩余部分
    • 返回较小的节点

执行结果

迭代版本:

  • 执行用时:84 ms
  • 内存消耗:38.5 MB

递归版本:

  • 执行用时:88 ms
  • 内存消耗:38.7 MB

总结与反思

  1. 这是一道经典的链表操作题目:
    • 考察基本的链表操作
    • 考察代码的简洁性
    • 考察边界情况的处理
  2. 两种解法比较:
    • 迭代:空间复杂度更低,代码直观
    • 递归:代码更简洁,但空间复杂度较高
  3. 优化思路:
    • 使用虚拟头节点简化操作
    • 使用空合并运算符简化代码
    • 注意处理边界情况

相关题目

posted @   旧厂街小江  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示