【LeetCode_21】合并两个有序链表

【LeetCode_21】合并两个有序链表

刷爆LeetCode系列

LeetCode第21题:

github地址

有梦想的电信狗

前言

  • 本文用C++解答LeetCode21

题目描述

题目链接https://leetcode-cn.com/problems/merge-two-sorted-lists/description/

在这里插入图片描述


在这里插入图片描述

题目与思路分析

目标分析

  1. 两个升序链表合并为一个升序链表
  2. 返回新链表的头指针
  3. 新链表中的结点由已有两链表中的节点组成
  4. 提高要求:时间复杂度为O(n),空间复杂度为O(1)

思路一:尾插

思路:创建一个新的空链表newHead同时逐个遍历两个链表的结点,将val较小的节点尾插到新链表中

操作

  • 注意对空链表的处理,两个链表可能都为空,也可能任意一个为空
  • 遍历:循环继续的条件为curNode1 && curNode2,只要有一个链表结束,结束即可,将未遍历完的链表直接整体尾插到新链表中
    • curNode1curNode2:分别用于遍历链表一和链表二
    • tailNode:尾结点,方便尾插时找尾
  • curNode->val <= curNode2->val时,说明:curNode1需要被尾插到新链表
    • 第一次尾插时(if(newHead == nullptr)需要特殊处理
      • tailNode = newHead = curNode;
      • curNode = curNode->next;
    • 其余结点的尾插,常规化处理
      • tailNode->next = curNode;
      • tailNode = tailNode->next;
    • 插入完后:curNode = curNode->next;
  • curNode->val > curNode2->val时和上面是一样的逻辑
  • 循环结束后,检查哪个链表未遍历完全直接整体尾插到新链表中
  • 最终返回return newHead;
// 循环结束后,可能链表还有剩余元素if(curNode1) tailNode->next = curNode1;if(curNode2) tailNode->next = curNode2;
在这里插入图片描述

思路二

思路:使用带哨兵位的头结点优化尾插,在带哨兵位的链表中进行尾插时,无需特殊处理第一次尾插时的情况

操作

  • 注意对空链表的处理,两个链表可能都为空,也可能任意一个为空
  • 遍历:循环继续的条件为curNode1 && curNode2,只要有一个链表结束,结束即可,将未遍历完的链表直接整体尾插到新链表中
    • curNode1curNode2:分别用于遍历链表一和链表二
    • tailNode:尾结点,方便尾插时找尾
  • curNode->val <= curNode2->val时,说明:curNode1需要被尾插到新链表
    • 有了哨兵位的头结点,结点的尾插,都能常规化处理
      • tailNode->next = curNode;
      • tailNode = tailNode->next;
    • 插入完后:curNode = curNode->next;
  • curNode->val > curNode2->val时和上面是一样的逻辑
  • 循环结束后,检查哪个链表未遍历完全直接整体尾插到新链表中
  • 保存新链表的头结点ListNode* newHead = guardNode->next,为guardNodenext结点
    • 释放guardNode防止内存泄露
  • 最终返回新的头结点return newHead;
 guardNode->next =nullptr;delete guardNode 
在这里插入图片描述

代码实现

思路一

classSolution{public: ListNode*mergeTwoLists(ListNode* list1, ListNode* list2){// 空链表判断if(list1 ==nullptr&& list2 ==nullptr)returnnullptr;if(list1 ==nullptr|| list2 ==nullptr){if(list1)return list1;if(list2)return list2;}// 以下 两个链表都不为空 ListNode* curNode1 = list1; ListNode* curNode2 = list2; ListNode* newHead =nullptr,*tailNode =nullptr;while(curNode1 && curNode2){// 更小的元素尾插到新结点if(curNode1->val <= curNode2->val){// 第一个节点直接尾插if(newHead ==nullptr){ newHead = tailNode = curNode1;}// 其他节点直接 尾插else{ tailNode->next = curNode1; tailNode = tailNode->next;} curNode1 = curNode1->next;}else{// 第一个节点直接尾插if(newHead ==nullptr){ newHead = curNode2; tailNode = curNode2;}// 其他节点直接 尾插else{ tailNode->next = curNode2; tailNode = tailNode->next;} curNode2 = curNode2->next;}}// 循环结束后,可能链表还有剩余元素if(curNode1) tailNode->next = curNode1;if(curNode2) tailNode->next = curNode2;return newHead;}};

思路二

// 使用带哨兵位的头结点 优化算法classSolution{public: ListNode*mergeTwoLists(ListNode* list1, ListNode* list2){if(list1 ==nullptr)return list2;if(list2 ==nullptr)return list1; ListNode* curNode1 = list1,*curNode2 = list2;// 遍历链表,用于迭代// 尾插需要找尾,提前保存,避免重复找 ListNode* guardNode =newListNode(); ListNode* tailNode = guardNode;while(curNode1 && curNode2){// 将小的那个结点,尾插到 guardNode 后面if(curNode1->val <= curNode2->val){ tailNode->next = curNode1; tailNode = tailNode->next; curNode1 = curNode1->next;}else{ tailNode->next = curNode2; tailNode = tailNode->next; curNode2 = curNode2->next;}}// 有一个链表结束后,将另一个链表再链接上if(curNode1) tailNode->next = curNode1;if(curNode2) tailNode->next = curNode2;// 保存新的头结点,并释放内存,防止内存泄露 ListNode* newHead = guardNode->next; guardNode->next =nullptr;delete guardNode;// 返回新结点return newHead;}};

算法代码优化

优化思路一

  • 优化了空链表返回的逻辑
  • 其中一个链表为空,就返回另一个链表
classSolution{public: ListNode*mergeTwoLists(ListNode* list1, ListNode* list2){if(list1 ==nullptr)return list2;if(list2 ==nullptr)return list1;// 以下 两个链表都不为空 ListNode* curNode1 = list1; ListNode* curNode2 = list2; ListNode* newHead =nullptr,*tailNode =nullptr;while(curNode1 && curNode2){// 更小的元素尾插到新结点if(curNode1->val <= curNode2->val){// 第一个节点直接尾插if(newHead ==nullptr){ newHead = tailNode = curNode1;}// 其他节点直接 尾插else{ tailNode->next = curNode1; tailNode = tailNode->next;} curNode1 = curNode1->next;}else{// 第一个节点直接尾插if(newHead ==nullptr){ newHead = curNode2; tailNode = curNode2;}// 其他节点直接 尾插else{ tailNode->next = curNode2; tailNode = tailNode->next;} curNode2 = curNode2->next;}}// 循环结束后,可能链表还有剩余元素if(curNode1) tailNode->next = curNode1;if(curNode2) tailNode->next = curNode2;return newHead;}};

优化思路二

  • 优化了初始链表判空的处理
  • 这里无需对空链表进行处理:通过分析得知
    • list1list2nullptr时,不会进入while循环。由于guardNode非空, ListNode* newHead = guardNode->next,因此保存的newHead时一定合法。
    • list1list2全为nullptr时,newHead即为nullptr
    • list1list2其中一个为nullptr时,newHead即另一个链表的头结点
// 使用带哨兵位的头结点 优化算法classSolution{public: ListNode*mergeTwoLists(ListNode* list1, ListNode* list2){// 遍历链表的结点 ListNode* curNode1 = list1,*curNode2 = list2;// 尾插需要找尾,提前保存,避免重复找 ListNode* guardNode =newListNode(); ListNode* tailNode = guardNode;while(curNode1 && curNode2){// 将小的那个结点,尾插到 guardNode 后面if(curNode1->val <= curNode2->val){ tailNode->next = curNode1; tailNode = tailNode->next; curNode1 = curNode1->next;}else{ tailNode->next = curNode2; tailNode = tailNode->next; curNode2 = curNode2->next;}}// 有一个链表结束后,将另一个链表再链接上if(curNode1) tailNode->next = curNode1;if(curNode2) tailNode->next = curNode2;// 保存新的头结点,并释放内存,防止内存泄露 ListNode* newHead = guardNode->next; guardNode->next =nullptr;delete guardNode;// 返回新结点return newHead;}};

以上就是本文的所有内容了,如果觉得文章对你有帮助,欢迎 点赞⭐收藏 支持!如有疑问或建议,请在评论区留言交流,我们一起进步

分享到此结束啦
一键三连,好运连连!
你的每一次互动,都是对作者最大的鼓励!征程尚未结束,让我们在广阔的世界里继续前行! 🚀

Read more

Python从0到100完整学习指南(必看导航)

Python从0到100完整学习指南(必看导航)

前言:零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学业升学和工作就业的先行者! 【优惠信息】 • 新专栏订阅前1000名享9.9元优惠 • 订阅量破1000后价格上涨至19.9元 • 订阅本专栏可免费加入粉丝福利群,享受: - 所有问题解答 - 专属福利领取 欢迎大家订阅专栏:零基础学Python:Python从0到100最新最全教程! 本文目录: * 一、Python基础与编程入门(第1-15篇) * 1.环境搭建与语法基础 * 2.数据结构基础篇 * 3.函数编程篇 * 二、面向对象与文件处理(第16-24篇) * 1.面向对象编程篇 * 2.标准库与文件处理篇 * 三、并发编程与网络爬虫(第25-39篇) * 1.并发编程基础篇

By Ne0inhk
python环境搭建(普通python、PyCharm )

python环境搭建(普通python、PyCharm )

步骤 1:安装 PyCharm 1. 访问 JetBrains 官网:https://www.jetbrains.com/pycharm/download/Download PyCharm: The Python IDE for data science and web development by JetBrains 2. 最后点击完成即可 下载完成后,运行安装程序,按照提示完成安装 向下滚动界面 找到PyCharm Community Edition 进行下载Community 版免费 选择适合你系统的版本(Community 版免费,Professional 版功能更丰富但需付费) 步骤 2:安装 Python 解释器 如果你还没有安装 Python,

By Ne0inhk
【C++】类和对象—(下) 收官之战

【C++】类和对象—(下) 收官之战

前言:上一篇文章我们向大家介绍了类和对象的核心六个成员函数中的4个,其余两个以及初始化列表,static成员,内部类,匿名对象等会在本篇文章介绍! ✨ 坚持用清晰易懂的图解+代码语言, 让每个知识点都简单直观! 🚀 个人主页 :MSTcheng · ZEEKLOG 🌱 代码仓库 :MSTcheng · Gitee 📌 专栏系列 :📖 《C语言》🧩 《数据结构》💡 《C++由浅入深》💬 座右铭 :“路虽远行则将至,事虽难做则必成!” 文章目录 * 一,运算符重载 * 1.1什么是运算符重载? * 1.2 为什么要创造运算符重载? * 二,赋值运算符重载 * 2.1赋值运算符重载的构成 * 2.1 >>流插入<<流提取重载 * 3.1const成员函数 * 4.1取地址运算符重载 * 三,初始化列表 * 3.

By Ne0inhk