leetcode 21. 合并两个有序链表(c++解法+相关知识点复习)

目录

题目

所需知识点复习

1.链表

1.1单链表

1.2哑结点(Dummy Node)

解答过程

1.循环+双指针解法

2.递归解法


2025.4.29想到其他知识点会后续再继续补充。

题目

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

示例 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.链表

链表(Linked List)是一种线性数据结构,由一系列的节点(Node)组成,每个节点包含:

1.数据域(val):存储数据

2.指针域(next):指向下一个节点

与数组不同,链表的内存不是连续存储的,而是通过指针连接各个节点。

1.1单链表

  • 每个节点包含val和next指针

  • 只能单向遍历(从头到尾)

  • 代码示例
  • struct ListNode {
        int val;
        ListNode *next;
        ListNode(int x) : val(x), next(nullptr) {}
    };
  • 判断链表是否为空:list1==nullptr

  • 在 C++ 中运算符的使用:

    • 当变量是对象实例时(如 ListNode dummy),使用 . 运算符访问成员(如 dummy.next
    • 当变量是指向对象的指针时(如 ListNode* l1),使用 -> 运算符访问成员(如 l1->val

1.2哑结点(Dummy Node)

哑结点(Dummy Node)是链表操作中常用的技巧,他是一个不存储实际数据的辅助节点,通常作为临时头节点,用于简化链表操作,尤其是在处理边界情况(如空链表、头节点变化等)时非常有用。(常用技巧,可以多加记忆!)

哑结点作用:

  1. 避免空指针异常:当链表可能为空时,使用哑结点可以确保始终有一个初始节点。
  2. 简化插入/删除操作:不需要单独处理头节点的特殊情况,所有操作都可以统一处理。
  3. 方便返回结果:最终返回 dummy.next 即可得到合并后的链表头,无需额外判断。
ListNode dummy(0);  // 创建一个哑结点,值为 0(值不重要)
ListNode* p = &dummy;  // p 是遍历指针,初始指向哑结点
  • dummy 是一个临时头节点,p 用于逐个连接 l1 和 l2 的节点。

  • 最终返回 dummy.next,因为 dummy.next 才是合并后的链表的真正头节点。

解答过程

毫无疑问,我自己没做出来,对链表知识点不熟悉了,紧急复习知识点,并学习了哑结点的使用。

我自己做是,想到了之前两个数组的排序采用的双指针,但是链表是不一样的。

采用循环+双指针的方法进行。方法二就是递归,这个也需要我好好理解一下。

1.循环+双指针解法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==nullptr) return l2;
        if(l2==nullptr) return l1;
        ListNode dummy(0);//哑结点用来简化操作
        ListNode* p=&dummy;//当前节点指针
        while(l1!=nullptr && l2!=nullptr){
            if(l1->val>=l2->val){//l1大于l2时,结果指向l2的值
                p->next=l2;
                //要移动的应该是指针,而不是直接赋值:eg:p=l2.val是错的。应该创建新节点并连接
                l2=l2->next;
            }else{//l1小于l2,结果指向l1的值
                p->next=l1;
                l1=l1->next;
            }
            p=p->next;
        }
        // if(l1!=nullptr){
        //     p->next=l1;
        // }
        // if(l2!=nullptr){
        //     p->next=l2;
        // }
        p->next=(l1!=nullptr)?l1:l2;//替换上面6行代码

        return dummy.next;
    }
};

2.递归解法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==nullptr) return l2;
        if(l2==nullptr) return l1;
        if(l1->val<l2->val){
            l1->next=mergeTwoLists(l1->next,l2);
            return l1;
        }
        l2->next=mergeTwoLists(l1,l2->next);
        return l2;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值