【牛客刷题-算法】加精 | 合并两个有序的链表 – 从思路设计、bug排除到最终实现的全过程

导读:本篇文章讲解 【牛客刷题-算法】加精 | 合并两个有序的链表 – 从思路设计、bug排除到最终实现的全过程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

个人主页-CSDN:清风莫追

🔥 该专栏作为刷题笔记,持续更新中。

推荐一款面试、刷题神器牛客网:👉开始刷题学习👈


1.题目描述

描述

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

数据范围: 0≤n≤1000,−1000≤节点值≤1000
要求:空间复杂度 O(1),时间复杂度 O(n)

如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6},转换过程如下图所示:

在这里插入图片描述

或输入{-1,2,4},{1,3,4}时,合并后的链表为{-1,1,2,3,4,4},所以对应的输出为{-1,1,2,3,4,4},转换过程如下图所示:

在这里插入图片描述

2.算法设计思路

1)总体思路:

以原链表中的值,新建一个链表,并保持有序。

如果直接将原链表中的结点接过来,问题会变得麻烦很多。我以前做过一次直接转移结点的,可参考:合并两个有序单链表,对象析构这一着我实在没想到

2)算法过程:

  1. 新建一个头指针 p,指向空。

  2. 使用两个指针 p1 和 p2 分别指向两个链表的头部,然后同时遍历两个链表。

  3. 每次遍历,创建一个新的结点连接到新链表尾部,然后比较 p1 和 p2 指向的结点中元素的值,并将较小的一个值存放到新结点中,同时相应的指针(p1 或 p2)向后移动一步。

  4. 停止遍历条件:p1 为空或 p2 为空。

  5. 将原链表中剩余元素的值转移到新链表中(如果有的话)。

3)遇到问题:

  1. 第一个结点的处理: 在创建新结点时,新链表可以处于两种状态:为空或不为空,因此需要分别考虑。
    if(p == nullptr){
                p = t;
                pHead = p;
            }else{
                p->next = t;
                p = p->next;
            }
  1. 原链表为空: 如果初始恰有一个原链表为空(另一个不为空),就会直接到第5步,转移原链表中的剩余元素,而此时新链表的头结点尚为空,操作p->next 就会出现问题。
//初始代码
    while(p3 != nullptr){
            p->next = new ListNode(0);
            p = p->next;
            p->val = p3->val;
            p3 = p3->next;
        }

可以仿照问题 1 的方式,加一个分支判断。

//修改方案一
//p3:指向第一个剩余的元素
    while(p3 != nullptr){
            if(p == nullptr){
                p = new ListNode(0);
                pHead = p;
            }else{
                p->next = new ListNode(0);
                p = p->next;
            }
            p->val = p3->val;
            p3 = p3->next;
        }

但这样的代码看起来比较难看。我们也可以在函数头部打个下面这样的“补丁”。

//修改方案二
    if(pHead1 == nullptr){
            return pHead2;
        }else if(pHead2 == nullptr){
            return pHead1;
        }

4)尝试优化代码

代码优化我目前觉得主要有两个方面:运行效率与可读性。我比较希望代码可以集中地的展现思路、更加简练

例如,关于遍历过程移动链表指针的操作,对比一下下面两段代码:

//代码段一
            if(x1 < x2){
                p1 = p1->next;
            }else{
                p2 = p2->next;
            }
//代码段二
            ListNode** p3 = x1 < x2 ? &p1 : &p2;
            *p3 = (*p3)->next;

我会比较喜欢第二段代码,因为它移动指针的操作就集中在一步:*p3 = (*p3)->next;

3.算法实现

注:这里并不是完整代码,而只是核心代码的模式

最终代码,C++实现:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        if(pHead1 == nullptr){
            return pHead2;
        }else if(pHead2 == nullptr){
            return pHead1;
        }

        ListNode* pHead = nullptr;
        ListNode* p = nullptr;
        ListNode* p1 = pHead1;
        ListNode* p2 = pHead2;

        while(p1 != nullptr && p2 != nullptr){
            ListNode* t = new ListNode(0);
            int x1 = p1->val;
            int x2 = p2->val;

            t->val = x1 < x2 ? x1 : x2;
            if(p == nullptr){
                p = t;
                pHead = p;
            }else{
                p->next = t;
                p = p->next;
            }

            ListNode** p3 = x1 < x2 ? &p1 : &p2;
            *p3 = (*p3)->next;
        }

        ListNode* p3 = nullptr;
        p3 = p1 != nullptr ? p1 : p2;

        while(p3 != nullptr){
            p->next = new ListNode(0);
            p = p->next;
            p->val = p3->val;
            p3 = p3->next;
        }
        return pHead;
    }
};

4.运行结果

成功通过!

在这里插入图片描述


结束语:

今天的分享就到这里啦,快来一起刷题叭!
👉开始刷题学习👈

在这里插入图片描述


感谢阅读

CSDN话题挑战赛第2期
参赛话题:学习笔记

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/114800.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!