LeetCode每日一题Day5——21. 合并两个有序链表

博主:命运之光 

🦄专栏:算法修炼之练气篇(C\C++版)

🍓专栏:算法修炼之筑基篇(C\C++版)

🐳专栏:算法修炼之练气篇(Python版)

博主的其他文章:点击进入博主的主页 

前言:欢迎来到这个LeetCode每日算法题专栏!

🌊无论你是编程新手还是有一定经验的开发者,掌握算法和数据结构都是成功的关键。在这个专栏里,我将每天为你分享一道算法题,并提供简单易懂的解析和讲解。

☀️通过每日挑战,你将逐渐培养解决问题的思维方式,掌握重要的编程技巧。无论是面试准备还是日常编码,这些知识都将对你大有裨益。

🎉让我们一起开始这段充满乐趣和成长的学习之旅吧!希望你能从中受益,开拓编程的新视野!

目录

21. 合并两个有序链表

正确答案

方法一:暴力破解

提交记录

详细解析该题代码(方法一:暴力破解)

方法二:递归法解题

提交记录

详细解析该题代码(方法二:递归法解题)

结语


21. 合并两个有序链表

正确答案

方法一:暴力破解

/**
 * 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) {
        ListNode dummy=ListNode(-1);
        ListNode *prev=&dummy;
        while(l1 != nullptr && l2 != nullptr){
            if(l1->val < l2->val){
                prev->next=l1;
                l1 = l1->next;
            }
            else{
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
        prev->next=l1==nullptr?l2:l1;
        return dummy.next;
    }
};

提交记录

详细解析该题代码(方法一:暴力破解)

这段代码是一个用于合并两个升序链表的C++函数,其中使用了单链表的数据结构。现在,我将逐行解析代码的功能:

  1. 定义了一个单链表的数据结构 ListNode,每个节点包含一个整数值 val 和一个指向下一个节点的指针 next。该数据结构提供了三个构造函数:
    • ListNode():无参构造函数,初始化 val 为0,next 为nullptr。
    • ListNode(int x):带参构造函数,初始化 val 为给定的整数x,next 为nullptr。
    • ListNode(int x, ListNode *next):带参构造函数,初始化 val 为给定的整数x,next 为指向给定节点的指针。
  1. 接下来是一个C++类 Solution 的定义。该类中有一个公共成员函数 mergeTwoLists,它用于合并两个升序链表。该函数接受两个指向链表头节点的指针 l1l2,并返回一个指向合并后链表头节点的指针。
  2. mergeTwoLists 函数中:
    • 创建了一个名为 dummyListNode 对象,并初始化其值为-1。这个 dummy 节点在合并过程中起到了哨兵节点的作用,它不包含实际数据,只是用来简化代码逻辑。
    • 创建一个指向 dummy 节点的指针 prev,用于跟踪合并后链表的末尾节点。
  1. 使用 while 循环进行链表的合并,循环条件是 l1l2 都不为nullptr(即还有节点需要合并)。
    • 在循环体中,比较 l1->vall2->val 的大小,如果 l1 的值小于 l2,则将 l1 添加到合并后链表的末尾,并将 l1 指针移动到下一个节点;否则,将 l2 添加到合并后链表的末尾,并将 l2 指针移动到下一个节点。
    • 然后,将 prev 指针移动到合并后链表的末尾。
  1. 当循环结束后,有可能 l1l2 中还有剩余节点未合并,此时需要将剩余的部分直接添加到合并后链表的末尾。这里使用了三目运算符 l1==nullptr?l2:l1 来确定应该将哪个链表的剩余部分添加到末尾。
  2. 最后,返回 dummy.next,即合并后链表的头节点的指针。由于 dummy 是一个临时节点,实际的合并后链表从 dummy.next 开始。

总体来说,这段代码通过迭代遍历两个升序链表,根据节点值的大小将节点逐个合并,并返回合并后的链表头节点的指针。合并后的链表仍然保持升序。

方法二:递归法解题

/**
 * 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;
        } else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

提交记录

详细解析该题代码(方法二:递归法解题)

除了迭代法外,还有递归法可以解决合并两个升序链表的问题。我将为你介绍递归法的解题思路和代码示例。

递归法的思路是基于合并两个升序链表的子问题。假设我们已经知道如何合并两个以 l1l2 为头节点的升序链表,我们可以将问题转化为合并以 l1->nextl2 为头节点的升序链表,并将结果连接到 l1 上。这样,问题规模不断缩小,最终合并两个链表的问题将转化为合并两个小一些的链表的问题,直到其中一个链表为空。

下面是用递归法解决问题的代码示例:

/**
 * 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;
        } else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

在递归函数 mergeTwoLists 中,我们首先处理边界情况,即如果其中一个链表为空,直接返回另一个链表。然后,我们比较 l1->vall2->val 的大小,如果 l1 的值小于 l2,则将 l1 的下一个节点与合并后的链表连接,并返回 l1;否则,将 l2 的下一个节点与合并后的链表连接,并返回 l2

递归法的思路较为简洁,但需要注意对递归深度的控制,防止出现栈溢出的情况。在实际应用中,可能需要对递归深度进行限制或使用迭代法来处理大规模的链表。

结语

再接再厉,继续加油!


本章的内容就到这里了,觉得对你有帮助的话就支持一下博主把~

🌌点击下方个人名片,交流会更方便哦~
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

命运之光

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值