每日一题---OJ题: 合并两个有序链表

news2024/11/25 5:47:50

嗨!小伙伴们,好久不见啦! 今天我们来看看一道很有意思的一道题---合并两个有序链表

嗯,题目看上去好像不难,我们一起画图分析分析吧!

上图中,list1有3个结点,分别为1,2,3 ; list2中有3个结点,分别为1,3,4, 题目要求我们要将这两个链表合并到一起,并且是升序,最后将链表返回。

思路1:定义2个变量,l1和l2,分别指向list1和list2,它们从头遍历链表,依次比较每个结点的数据域,如果l1指向的结点的数据域小于l2指向的结点的数据域,那么就将l1尾插到新链表中; 反之亦然。

当 l1 && l2 不为空的时候,进入while循环(注意是 &&,因为只要有一个不满足条件,就可以跳出while循环),判断第一个结点,判断完毕后,尾插到新链表中(如果新链表为空,那么这个结点就是链表的头结点和尾结点 ; 如果链表不为空,这个结点就是链表的新的尾结点)。

第一次:  将list2中第一个结点尾插到新链表中,该结点就是链表的头结点和尾结点。l2继续往后遍历链表。

第二次:l1指向的结点的数据域小于l2,因此将该结点尾插到新链表中,这个结点就是链表的新的尾结点,l1指向下一个结点。

第三次:l1指向的结点的数据域小于l2,因此将该结点尾插到新链表中,这个结点就是链表的新的尾结点,l1指向下一个结点。

第四次: l2指向的结点的数据域小于l1,因此将该结点尾插到新链表中,这个结点就是链表的新的尾结点,l2指向下一个结点。

第五次:

第六次:

好啦,大致思路就是这样,接下来我们开始实现吧!

首先,定义2个变量l1和l2,分别指向list1和list2; 其次,我们定义新链表的表头newHead和表尾newTail。

struct ListNode* l1 = list1;                    //定义l1变量,指向list1
struct ListNode* l2 = list2;                    //定义l2变量,指向list2

struct ListNode* newHead = NULL;                //定义新链表的头结点
struct ListNode* newTail = NULL;                //定义新链表的尾结点

当  l1 && l2不为空,进入循环,依次比较每一个结点。

 while( l1 && l2){
    if(l1->val < l2->val){
          //l1比l2小
    if(newTail == NULL){
         //如果链表为空
        newHead = newTail = l1;
     }else{
        //链表不为空
        newTail->next = l1;
        newTail = l1;
      }
    l1 = l1->next;        //l1指向下一个结点

   }else{
        //l2比l1小
    if(newTail == NULL){
        //如果链表为空
        newHead = newTail = l2;
       }else{
        //链表不为空
        newTail->next = l2;
        newTail = l2;
      }
    l2 = l2->next;        //l2指向下一个结点
   }
}

是不是这里就结束了呢? 当然不是! 当 l1 走到NULL的位置 或者 l2 走到空的位置, 会跳出循环,来到后面的代码。

当 l1还未遍历完链表时,我们只需要将 newTail的next指针指向 l1 就可以啦! 用 if条件来做判断,本身就只让它执行一次,因为链表最后剩下的,就直接往后挂了,链表的每一个结点是通过next指针链接的,找到一个结点,就可以找到后续的所有结点。

(就像老鹰捉小鸡一样,是不是从中间折断的话,那后面的那些人还是连在一起的,重新连接的话,那只用把后半段的第一个人找到,挂回去,那后面的人也就一并连接回去了。)

if(l1){
        //l1没有遍历完链表
        newTail->next = l1;
    }
    if(l2){
        //l2没有遍历完链表
        newTail->next = l2;
    }

好啦,最后我们返回newHead就可以啦! 但是还有一个小小的问题需要注意: 传过来的参数 list1 或者 list2 有可能为空, 因此我们需要在开始就判断一下它们是否为空。

 if(list1 == NULL){
        //如果list1为空,则返回list2
        return list2;
    }

    if(list2 == NULL){
        //如果list2为空,则返回list1
        return list1;
    }

OK,整体代码如下: 

 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if(list1 == NULL){
        //如果list1为空,则返回list2
        return list2;
    }

    if(list2 == NULL){
        //如果list2为空,则返回list1
        return list1;
    }

    ListNode* l1 = list1;//定义l1变量,指向list1
    ListNode* l2 = list2; //定义l2变量,指向list2

    ListNode* newHead = NULL; //定义新链表的头结点
    ListNode* newTail = NULL; //定义新链表的尾结点

 while( l1 && l2){
    if(l1->val < l2->val){
          //l1比l2小
    if(newTail == NULL){
         //如果链表为空
        newHead = newTail = l1;
     }else{
        //链表不为空
        newTail->next = l1;
        newTail = l1;
      }
    l1 = l1->next;        //l1指向下一个结点

   }else{
        //l2比l1小
    if(newTail == NULL){
        //如果链表为空
        newHead = newTail = l2;
       }else{
        //链表不为空
        newTail->next = l2;
        newTail = l2;
      }
    l2 = l2->next;      //l2指向下一个结点
   }
}

    if(l1){
        //l1没有遍历完链表
        newTail->next = l1;
    }
    if(l2){
        //l2没有遍历完链表
        newTail->next = l2;
    }
    return newHead; //返回头结点
}

好的,这道题我们基本上做完了,可是,看看这代码,好像有重复冗余的部分,我们如何优化代码呢? 

答案是: 我们可以定义一个哨兵结点,这个结点可以不存放数据,让它指向新链表的头结点。 

    ListNode* node =(ListNode*) malloc(sizeof(ListNode));   //创建一个哨兵结点
    ListNode* newHead = node;                               //头结点指向哨兵结点
    ListNode* newTail = node;                               //尾结点指向哨兵结点

中间的循环也需要更改,不用判断链表是否为空了。

 while( l1 && l2){
    if(l1->val < l2->val){
    //       //l1比l2小
    // if(newTail == NULL){
    //      //如果链表为空
    //     newHead = newTail = l1;
    //  }else{
    //     //链表不为空
    //     newTail->next = l1;
    //     newTail = l1;
    //  }
        newTail->next = l1;
        newTail = l1;
        l1 = l1->next;        //l1指向下一个结点
      }else{
        //l2比l1小
    // if(newTail == NULL){
    //     //如果链表为空
    //     newHead = newTail = l2;
    //    }else{
    //     //链表不为空
    //      newTail->next = l2;
    //      newTail = l2;
        newTail->next = l2;
        newTail = l2;
        l2 = l2->next;      //l2指向下一个结点
   }
}

malloc了空间,但这块空间实际上用不了,最后我们需要将哨兵结点释放

    //malloc了空间,但这块空间实际上用不了,应该将其释放掉
    ListNode* ret = newHead->next;
    free(newHead);
    return ret; //返回头结点的下一个结点

好啦,优化过的代码如下:

 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if(list1 == NULL){
        //如果list1为空,则返回list2
        return list2;
    }

    if(list2 == NULL){
        //如果list2为空,则返回list1
        return list1;
    }

    ListNode* l1 = list1;//定义l1变量,指向list1
    ListNode* l2 = list2; //定义l2变量,指向list2

    ListNode* node =(ListNode*) malloc(sizeof(ListNode));   //创建一个哨兵结点
    ListNode* newHead = node;                               //头结点指向哨兵结点
    ListNode* newTail = node;                               //尾结点指向哨兵结点

 while( l1 && l2){
    if(l1->val < l2->val){
    //       //l1比l2小
    // if(newTail == NULL){
    //      //如果链表为空
    //     newHead = newTail = l1;
    //  }else{
    //     //链表不为空
    //     newTail->next = l1;
    //     newTail = l1;
    //  }
        newTail->next = l1;
        newTail = l1;
        l1 = l1->next;        //l1指向下一个结点
      }else{
        //l2比l1小
    // if(newTail == NULL){
    //     //如果链表为空
    //     newHead = newTail = l2;
    //    }else{
    //     //链表不为空
    //      newTail->next = l2;
    //      newTail = l2;
        newTail->next = l2;
        newTail = l2;
        l2 = l2->next;      //l2指向下一个结点
   }
}

//跳出循环存在两种情况,要么l1走到空l2不为空,要么l2走到空,l1不为空
//不可能存在都为空的情况

    if(l1){
        //l1没有遍历完链表
        newTail->next = l1;
    }
    if(l2){
        //l2没有遍历完链表
        newTail->next = l2;
    }

    //malloc了空间,但这块空间实际上用不了,应该将其释放掉
    ListNode* ret = newHead->next;
    free(newHead);
    return ret; //返回头结点的下一个结点
}

OK,今天的讲解到这里就结束啦,我们下期再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JAVA基础篇教学】第六篇:Java异常处理

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第五篇&#xff1a; Java异常处理。 异常处理是Java编程中重要的一部分&#xff0c;它允许开发人员在程序运行时检测和处理各种错误情况&#xff0c;以保证程序的稳定性和可靠性。在Java中&#xff0c;异常被表示为对象&am…

大型网站系统架构演化

大型网站质量属性优先级&#xff1a;高性能 高可用 可维护 应变 安全 一、单体架构 应用程序&#xff0c;数据库&#xff0c;文件等所有资源都在一台服务器上。 二、垂直架构 应用和数据分离&#xff0c;使用三台服务器&#xff1a;应用服务器、文件服务器、数据服务器 应用服…

TCM SRAM等五块内存的使用和动态分配

TCM SRAM等五块内存的使用和动态分配 配置sct文件内存使用动态内存分配rtx_lib.hrtx_memory.cmain.c 配置sct文件 LR_IROM1 0x08000000 0x00200000 { ; load region size_regionER_IROM1 0x08000000 0x00200000 { ; load address execution address*.o (RESET, First)*(InRoo…

1113. 红与黑--Flood Fill 算法

目录 1113. 红与黑--Flood Fill 算法---宽搜&#xff08;BFS&#xff09;或DFS&#xff09; 输入格式 输出格式 数据范围 输入样例&#xff1a; 输出样例&#xff1a; 思路&#xff1a; 1.BFS 思路&#xff1a; 2.DFS 思路 方法一&#xff1a;&#xff08;BFS&#x…

玉伯也创业了,曾经的互联网高P也慢慢的落幕了

玉伯是真创业还是被动创业&#xff1f;毕竟&#xff0c;在阿里的时候&#xff0c;他可是Ant Design和语雀的大佬&#xff0c;风光无限&#xff0c;谁都知道他的大名。但后来&#xff0c;他去了字节&#xff0c;待了不到一年就跑了&#xff0c;现在选择出来创业。是不是曾经的那…

文章分享:《二代测序临床报告解读指引》

&#xff3b;摘要&#xff3d; 二代测序&#xff08;next generation sequencing&#xff0c;NGS&#xff09;已成为中国临床肿瘤医生常用检测工具&#xff0c;而中国超 90%临床医生需要 NGS 报告解读支持。因此&#xff0c;为提升临床医生 NGS 报告解读能力&#xff0c;特编写…

ETL结合飞书快速实现业务信息同步

一、ETL工具介绍 ETLCloud数据集成平台是一款针对IT以及数据工程师推出的全域数据集成平台产品。它是集实时数据集成和离线数据集成以及API发布为一体的数据集成平台。与其他开源数据集成工具相比&#xff0c;系统采用轻量化架构、具有更快的部署速度、更快的数据传输速度、更…

宏景eHR customreport/tree SQL注入漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR customreport/tree 接口处存在SQL注入漏洞,未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令,从而窃取数据库…

HarmonyOS-数据请求(http / axios)

一、http数据请求 步骤&#xff1a; 1.在module.json5中申请ohos.permission.INTERNET权限 "module": {"requestPermissions": [{ "name": "ohos.permission.INTERNET" }],...} 2.在xxx.ets页面中导入&#xff1a;import http fro…

RPC简单介绍

Rpc框架&#xff0c;来为模块间远程功能交互提供⽀撑&#xff1b; 这个Rpc框架中有诸如RpcServer、RpcService、RpcSystem、RpcEndpoint等⼤量设计封装&#xff1b; 1. 基本概念 RPC&#xff1a;远程过程调⽤&#xff08;Remote Procedure Call&#xff09;&#xff1b; •…

库、框架、脚手架和IDE一文讲明白

在区分上面几个问题前&#xff0c;咱们先看看几个疑问。 一、常见问题汇总 js css直接复制到服务器 然后引用不就行了么&#xff1f; 为什么还需要安装&#xff1f; 引入js不就是引入了框架了吗&#xff1f;框架就是js&#xff1f; 脚手架和框架都有架&#xff0c;是不是一…

国家留学基金委(CSC)2024-2025年度中加学者交换项目开始申报

4月3日&#xff0c;国家留学基金委&#xff08;CSC&#xff09;发布了2024-2025年度中加学者交换项目遴选通知。根据通知精神&#xff0c;选派规模&#xff1a;100人月&#xff0c;留学及资助期限&#xff1a;4-12个月&#xff0c;网上报名截止日期至2024年6月30日。以下知识人…

基于SSM+Vue实现的宠物销售系统

基于SSMVue实现的宠物销售系统 系统介绍 系统演示 点击查看视频演示 基于SSMVue实现的宠物销售系统&#xff0c;主要实现的功能有以下几点&#xff1a;管理员&#xff1b;首页、个人中心、宠物分类管理、商品分类管理、宠物用品管理、宠物商店管理、宠物领养管理、用户管理…

UI状态伪类选择器

1.div::selection{background:yellow;color: red; } 鼠标选中后高亮状态的样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge">&…

题目:建造房屋 (蓝桥OJ3362)

问题描述: 代码: #include<bits/stdc.h> using namespace std; int n, m, k, ans, mod 1e9 7; long long dp[55][2605]; /*dp[i][j]&#xff1a;第i个街道上建j个房屋的总方案数枚举所有的转移&#xff0c;累加到dp[n][k]即总方案数 */ int main() {cin >> n &…

JavaEE 初阶篇-深入了解 CAS 机制与12种锁的特征(如乐观锁和悲观锁、轻量级锁与重量级锁、自旋锁与挂起等待锁、可重入锁与不可重入锁等等)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 乐观锁与悲观锁概述 1.1 悲观锁&#xff08;Pessimistic Locking&#xff09; 1.2 乐观锁&#xff08;Optimistic Locking&#xff09; 1.3 区别与适用场景 2.0 轻…

Linux虚拟网络设备:底层原理与性能优化深度解析

在深入探讨Linux虚拟网络设备的底层原理之前&#xff0c;重要的是要理解这些设备如何在Linux内核中实现&#xff0c;以及它们如何与操作系统的其他部分交互以提供高效且灵活的网络功能。虚拟网络设备在现代网络架构中发挥着关键作用&#x1f511;&#xff0c;特别是在云计算☁️…

Playwright录制脚本 —— web自动化测试!

简介&#xff1a; 在编写 web 自动化测试用例时&#xff0c;代码编写的速度是否快&#xff0c;会影响框架的使用体验。现在很多的框架都会提供一些辅助功能&#xff0c;帮助我们更快的去编写自动化测试代码&#xff0c;而录制功能是几乎所有的web自动化工具都会带的功能。在实际…

ASUS华硕灵耀Pro14笔记本AMD锐龙版M7400QC,M7600QA原厂Win11系统工厂包下载

恢复华硕灵耀14PRO出厂开箱状态预装OEM系统Windows11工厂模式安装包&#xff0c;带Recovery恢复还原功能 适用型号&#xff1a; M7400QC、M7400QE、M7400QEB M7600QC、M7600QE、M7600QA、M7600QCB 链接&#xff1a;https://pan.baidu.com/s/1dIGRAKJQLQt_JcKbQWFxJg?pwdbn…

VBA_NZ系列工具NZ05:VBA不打开工作簿获取其内容

我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#xff0c;这么多知识点该如何组织…