LeetCode题练习与总结:合并两个有序链表

254 篇文章 0 订阅
70 篇文章 0 订阅
本文介绍了如何将两个已排序的链表合并成一个新的升序链表,通过创建虚拟头节点、使用指针遍历并比较节点值,最后返回新链表的头节点。代码的时间复杂度为O(m+n),空间复杂度为O(1)。
摘要由CSDN通过智能技术生成

一、题目描述

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

示例 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
  • l1l2 均按 非递减顺序 排列

二、解题思路

  1. 创建一个新的虚拟头节点,这个节点不会包含任何实际的值,它的目的是为了简化边界条件处理,比如在合并完成后直接返回头节点的下一个节点作为新链表的头节点。
  2. 创建一个当前指针(current),初始指向虚拟头节点。
  3. 使用两个指针分别指向两个链表的当前节点,分别为p1p2,初始时p1指向list1的头节点,p2指向list2的头节点。
  4. 进入一个循环,循环条件是p1p2都不为空。
  5. 在每次循环中,比较p1p2的值,将较小的节点连接到current后面,然后将对应的指针向前移动一位。
  6. 如果其中一个链表的指针已经移动到末尾,将另一个链表剩余的所有节点连接到current后面。
  7. 当两个链表的所有节点都处理完毕后,返回虚拟头节点的下一个节点,即新链表的头节点。

三、具体代码

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // 创建虚拟头节点
        ListNode dummy = new ListNode(0);
        // 当前指针,初始指向虚拟头节点
        ListNode current = dummy;
        
        // 初始化两个链表的指针
        ListNode p1 = list1, p2 = list2;
        
        // 当两个链表都不为空时循环
        while (p1 != null && p2 != null) {
            // 比较两个节点的值,选择较小的节点
            if (p1.val < p2.val) {
                current.next = p1;
                p1 = p1.next;
            } else {
                current.next = p2;
                p2 = p2.next;
            }
            // 移动当前指针
            current = current.next;
        }
        
        // 如果一个链表为空,将另一个链表的剩余部分连接到当前链表
        if (p1 != null) {
            current.next = p1;
        } else if (p2 != null) {
            current.next = p2;
        }
        
        // 返回新链表的头节点
        return dummy.next;
    }
}

四、时间复杂度与空间复杂度

这段代码的时间复杂度是 O(m + n),空间复杂度是 O(1)。

1. 时间复杂度
  • 代码中的循环会遍历两个链表中的所有元素,直到其中一个链表的所有元素都被处理完毕。
  • 在最坏的情况下,即两个链表长度相等,循环会执行大约 m + n 次,其中 mlist1 的长度,nlist2 的长度。
  • 因此,时间复杂度是 O(m + n)。
2. 空间复杂度
  • 创建了一个虚拟头节点 dummy,它是一个常数级别的额外空间。
  • current 指针在循环中被重复使用,指向新链表的当前节点,这不会增加额外的空间复杂度。
  • 除了输入链表外,没有使用额外的数据结构来存储链表元素,所以空间复杂度是 O(1),即常数空间复杂度。

五、总结知识点

1. 链表(Linked List)

  • 链表是一种线性数据结构,其中的元素(节点)按顺序链接在一起。
  • 每个节点包含数据部分(val)和指向下一个节点的指针(next)。

2. 虚拟头节点(Dummy Node)

  • 在处理链表问题时,有时会创建一个虚拟头节点,它的目的是简化边界条件的处理,如在合并链表时不需要特别处理头节点。

3. 指针操作

  • 使用指针(p1p2)遍历和操作链表。
  • 在循环中,指针用于比较和选择两个链表中的较小节点,并更新指针以指向下一个节点。

4. 条件语句(Conditional Statement)

  • 使用if-else语句来决定哪个节点应该成为新链表的一部分。

5. 循环(Loop)

  • 使用while循环来遍历两个链表,直到其中一个链表的所有元素都被处理。

6. 链表的连接

  • 在循环中,通过更新current.next来连接两个链表的节点,形成新的链表。

7. 边界条件处理

  • 在循环结束后,需要检查两个链表是否还有剩余的节点,如果有,需要将剩余的节点连接到新链表的末尾。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值