【LeetCode题目详解】(三)21.合并两个有序链表、141.环形链表、142.环形链表Ⅱ

news2024/11/17 3:05:50

目录

一、力扣第21题:合并两个有序链表

解法思路

代码一

代码二

代码三

二、力扣第141题:环形链表

1.快慢指针法

2.证明快慢指针是可行的

三、力扣第142题:环形链表Ⅱ

1.解题思路

2.代码

总结


一、力扣第21题:合并两个有序链表

题目链接:21. 合并两个有序链表 - 力扣(Leetcode)

题目描述:

 

解法思路

对于这个题目而言,我们肯定是很熟悉的,因为我们已经讲解过一个合并两个有序数组的题目了。这道题完全只是将数组改成了链表。那么我们在链表中使用的方法是尾插法。谁小先插谁

我们先过一遍思路吧,首先我们先看这个图

我们的思路是这样的,先创建两个指针,newHead和tail,用于记录最后返回的链表的头和尾,我们让他们一开始指向NULL

 然后我们看如果list1->val<list2->val时,我们就让newHead和tail都指向list1,然后tail向后走一步,list向后走一步,反之则移动执行另外一个链表的操作,如下图所示

 然后我们一直循环下去

 

 

 

 当只要有一个链表为空以后,那么直接将两个链表链接起来即可

 

 这就是我们的大体思路,但是需要注意的是,有可能一开始会有其中一个链表是空链表,那么这种我们可以一开始做一个判断,只要有一个为空,返回另外一个链表即可

代码一

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    //特殊情况的处理
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    //定义返回链表的头和尾部
    struct ListNode* newHead=NULL;
    struct ListNode* tail=NULL;
    //只要两个都不是空链表那么就可以继续执行下去
    while(list1 && list2)
    {
        //1的值小于2的值时
        if(list1->val<list2->val)
        {
            //链表头为空,这是第一次插入,需要特殊处理
            if(newHead==NULL)
            {
                newHead=tail=list1;
                list1=list1->next;
            }
            //正常情况处理
            else
            {
                tail->next=list1;
                list1=list1->next;
                tail=tail->next;
            }
        }
        //1的值大于等于2的值时
        else
        {
            //链表头为空,是第一次插入,需要特殊处理
            if(newHead==NULL)
            {
                newHead=tail=list2;
                list2=list2->next;
            }
            //正常情况处理
            else
            {
                tail->next=list2;
                tail=tail->next;
                list2=list2->next;
            }
        }
    }
    if(list1==NULL)
    {
        tail->next=list2;
    }
    else
    {
        tail->next=list1;
    }
    return newHead;
}

运行结果为

代码二

其实我们可以将上面的代码进行简化处理,我们可以在循环内只处理尾插,第一个结点放在外面处理

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    //特殊情况的处理
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    //定义返回链表的头和尾部
    struct ListNode* newHead=NULL;
    struct ListNode* tail=NULL;
    //处理头节点
    if(list1->val < list2->val)
    {
        newHead=tail=list1;
        list1=list1->next;
    }
    else
    {
        newHead=tail=list2;
        list2=list2->next;
    }
    //只要两个都不是空链表那么就可以继续执行下去
    while(list1 && list2)
    {
        //1的值小于2的值时
        if(list1->val<list2->val)
        {
            //尾插
            tail->next=list1;
            list1=list1->next;
            tail=tail->next;

        }
        //1的值大于等于2的值时
        else
        {
            //尾插
            tail->next=list2;
            tail=tail->next;
            list2=list2->next;
        }
    }
    if(list1==NULL)
    {
        tail->next=list2;
    }
    else
    {
        tail->next=list1;
    }
    return newHead;
}

代码三

其实我们还可以使用一个哨兵位来解决第一个头节点的问题

代码如下

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    //特殊情况的处理
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    //定义返回链表的头和尾部
    struct ListNode* newHead=NULL;
    struct ListNode* tail=NULL;
    newHead=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
    //只要两个都不是空链表那么就可以继续执行下去
    while(list1 && list2)
    {
        //1的值小于2的值时
        if(list1->val<list2->val)
        {
            //尾插
            tail->next=list1;
            list1=list1->next;
            tail=tail->next;

        }
        //1的值大于等于2的值时
        else
        {
            //尾插
            tail->next=list2;
            tail=tail->next;
            list2=list2->next;
        }
    }
    if(list1==NULL)
    {
        tail->next=list2;
    }
    else
    {
        tail->next=list1;
    }
    return newHead->next;
}

二、力扣第141题:环形链表

题目链接:141. 环形链表 - 力扣(Leetcode)

题目描述:

 

1.快慢指针法

其实这个题我们思考一下,如果它是一个环的话,那我们遍历一遍它就进入死循环了,如果不是环,就可以出来,但是这我们又无法知道它是否是死循环。有可能数据无限大,所以我们不能简单的凭借是否死循环来做这道题,那么就想,我们高中物理学过追及相遇问题,那么我们同样可以将思路带入到这里来。

我们是这样想的,使用两个指针,一个一次走一步,一个一次走两步。如果有环的话,那么快慢最终会相遇(下面有证明),如果无环,那么最终fast或者fast->next中必然有一个为空,因为有奇偶的讨论。所以顺着这个思路,这个代码很容易就写出来了

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head;
    struct ListNode* fast=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

2.证明快慢指针是可行的

我们了解了上面的解法以后,我们也会产生一些疑惑,为什么快慢指针一定相遇,这里和物理中的追及相遇问题不一样的是,追及相遇问题是连续的,而这个问题是离散的。

我们的问题归纳一下就是:

slow一次走一步,fast一次走两步

1.slow和fast最后一定会相遇吗?有没有可能不会相遇?

2.slow一次走一步,fast一次走三步行不行?

slow一次走一步,fast一次走四步行不行

请证明:

我们先给出结论:

slow一次走一步,fast一次走两步一定可以相遇

我们可以这样思考

假设当slow刚进环的时候,fast和slow距离为N

那么fast和slow每一次他们的距离就-1,距离为N-1N-2 N-3...........0

最终一定会变为0。也就是相遇了。

所以一定可以相遇

那么slow一次一步,fast一次三步可不可以呢?

我们同样假设slow刚进环的时候相距为N

那么它们最终的距离就为N-2 N-4 N-6..........

我们可以看出来他们最终是要分情况讨论的,他们距离最近时候要么为0 要么为-1

0代表相遇,但是-1呢?-1其实代表着fast反超了slow一步

这时候我们假设环的总长度为C

那么我们此时fast和slow就相距为C-1的长度,而走一次他们的距离就减2

那么我们也可以看出来,当C为偶数的时候,永远不可能相遇

当C为奇数的时候才会相遇

所以fast一次走三步的时候还取决于N和C的长度。不一定会相遇

同样的,当一次走四步的时候也是同理的,不一定相遇

三、力扣第142题:环形链表Ⅱ

题目链接:142. 环形链表 II - 力扣(Leetcode)

题目描述:

 

1.解题思路

对于这道题,难点就在于如何求出这个入口,我们先给出结论

一个指针从相遇点走,一个指针从开头走,最终这两个指针将会在入口相遇

对于这个题目我们得先画图思考一下,如下图所示,假设这就是我们的链表

 设环为C长度,他们相遇点距离入口为X长度,他们的起始点距离入口为L长度

 已经fast的路程为L+X+N*C,slow的路程为X+L

slow的路程很简单,因为slow进入环以后,fast一定会在一圈之内追上slow,所以为L+X

这里大家比较疑惑的就是fast的路程,其实fast的路程是这样得到的,首先fast得先走一个L,这个毋庸置疑,然后当slow进环的时候,fast刚好走了一段距离,现在是fast正在追slow,这个时候slow走了x的时候,fast也刚好追上slow。而fast这时候其实就相当于走了N*C+X路程了,因为有可能直线特别大,圈特别小,fast在圈内走了好多圈了,slow还没有进来。所以走了N*C圈

 而又由于fast的速度是slow的两倍,时间相同,那么路程肯定也是两倍

所以得出

N*C+X+L=2*(X+L)

然后得出

N*C-X=L

而这个公式的含义就是

一个指针从相遇点走,一个指针从开头走,最终这两个指针将会在入口相遇

2.代码

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            struct ListNode* meet=slow;
            while(meet!=head)
            {
                meet=meet->next;
                head=head->next;

            }
            return meet;
        }
    }
    return NULL;
}


总结

本小节讲解了三个经典的力扣题21.合并两个有序链表、141.环形链表、142.环形链表Ⅱ,希望大家都学会

如果对你有帮助,不要忘记点赞加收藏哦!!!

想获得更多有优质的内容,那么一定要关注我哦!!!

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

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

相关文章

selenium自动化测试

文章目录1.什么是自动化测试2.UI自动化测试3, webdriver的原理元素的定位定位操作示例操作测试对象添加等待固定等待智能等待打印信息浏览器的操作浏览器最大化设置浏览器宽、高操作浏览器的前进、后退控制浏览器滚动条键盘事件键盘按键用法键盘组合键用法鼠标事件ActionChains…

接口测试(七)—— 参数化、数据库操作封装、接口自动化框架

目录 一、接口自动化测试框架 1、目录结构 二、封装iHRM登录 1、普通方式实现 2、登录接口对象层 3、登录接口测试用例层 4、封装断言方法 三、参数化 1、回顾UnitTest参数化 1.1 原始案例 1.2 参数化实现 1.3 从json文件读取 2、登录接口参数化 2.1 组织数据文…

ArcGIS:如何进行离散点数据插值分析(IDW)、栅格数据的重分类、栅格计算器的简单使用、缓冲区分析、掩膜?

目录 01 说明 02 实验目的及要求 03 实验设备及软件平台 04 实验内容与步骤 4.1 反距离权重插值分析 4.2 多栅格局域运算 4.3 按表格显示分区统计 4.4 重分类 4.5 邻域运算 4.6 矢量数据的裁剪 4.7 缓冲区分析及栅格数据提取分析 05 思考及讨论 01 说明 由于这次的作业是从word…

jsp+ssm计算机毕业设计宠物寻回系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

2.两数相加

正在建设中 传送门&#xff1a; https://leetcode.cn/problems/add-two-numbers/ 题目描述 给你两个非空的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照逆序的方式存储的&#xff0c;并且每个节点只能存储一位数字。 请你将两个数相加&#xff0c;并以相同形…

git 进阶系列教程-------git使用流程

GIT使用流程 前言 初衷 git是一门很容易入门的项目管理工具&#xff0c;但是它是一门很难精通的技术。 git pull/git add ./git commit -m "message"/git push/......知道以上几个命令&#xff0c;或许再多一点&#xff0c;也许就能说&#xff1a;‘我会git’了。…

IDEA画UML类图

第一步(IDEA下载画图插件) PlantUML Integration 插件可以支持画图 第二步(创建类图文件) 点击之后会让选择 选择class即可 类图的语法 在画类图的时候分为五种 1. 依赖 依赖分为好多种&#xff0c; 作为成员变量&#xff0c;作为方法的入参和出参&#xff0c;在类中使用…

【JSP菜鸟教程】

简介 JSP是一种Java servlet&#xff0c;主要用于实现Java web应用程序的用户界面部分。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束。 Scriptlet脚本小程序 如果你想在HTML中写Java代码&#xff0c;就需要将Java代码写入Scriptlet中&#xff0…

数据库实验一:数据定义与操作语言实验

实验一 数据定义与操作语言实验 实验 1.1 数据库定义实验 1.实验目的 理解和掌握数据库DDL语言&#xff0c;能够熟练地使用SQL DDL语句创建、修改和删除数据库、模式和基本表。 2.实验内容和要求 理解和掌握SQL DDL语句的语法&#xff0c;特别是各种参数的具体含义和使用方…

第十七届D2大会(I)

一、Web Compass-端内Web App解决方案揭秘 增强传统web端内方案&#xff0c;提供更好、更收敛的工程体验 二、自渲染跨端框架在字节跳动的实践与展望 基于Flutter Engine的二次开发 三、Qking&#xff1a;跨端JS引擎的深度探索与突破 常见js引擎&#xff0c;如&#xff1a;v8…

CSC7268

CSC7268概述: CSC7268是一款内置高压MOS的高性能、多工作模式的PWM控制芯片&#xff0c;内置多种保护机制。当系统为空载和轻载时&#xff0c;CSC7268采用Burst和Green控制模式可有效地减少了空载和轻载时的损耗。当系统为中载和重载时&#xff0c;芯片采用QR模式和CCM模式可有…

python基础: filter, lambda 函数表达式

filter(function or None, sequence)&#xff0c;其中sequence 可以是list ,tuple,string。这个函数的功能是过滤出sequence 中所有以元素自身作为参数调用function时返回True或bool(返回值)为True的元素并以列表返回. filter只能接受两个参(function,sequence) &#xff0c;其…

Biotin-PEG-SH,Biotin-PEG-Thiol,生物素PEG巯基PEG衍生物供应

英文名称&#xff1a;Biotin-PEG-Thiol&#xff0c;Biotin-PEG-SH 中文名称&#xff1a;生物素-聚乙二醇-巯基 生物素-PEG-SH通过与链霉亲和素或抗生物素结合进行聚乙二醇化&#xff0c;具有高亲和力和特异性。生物素通过稳定的酰胺连接物与线性PEG结合。它具有与马来酰亚胺选…

java 瑞吉外卖day3 公共字段自动填充 新增分类

公共字段自动填充 代码实现 1. TableField(fill FieldFill.INSERT)//插入时填充字段 private LocalDateTime createTime;TableField(fill FieldFill.INSERT_UPDATE)//插入和更新时填充字段 private LocalDateTime updateTime;TableField(fill FieldFill.INSERT) private Lo…

数据库实验六:存储过程实验

实验六 存储过程实验 实验6.1 存储过程实验 1.实验目的 ​ 掌握数据库PL/SQL编程语言&#xff0c;以及数据库存储过程的设计和使用方法。 2.实验内容和要求 ​ 存储过程定义&#xff0c;存储过程运行&#xff0c;存储过程更名&#xff0c;存储过程删除&#xff0c;存储过程…

[附源码]Python计算机毕业设计Django少儿节目智能推荐系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Oracle数据的备份和恢复

Oracle数据的备份和恢复 ​ 当我们使用一个数据库时,总希望数据是可靠的、正确的,但由于计算机系统的故障(硬件故障、软件故障、网络故障、进程故障和系统故障)影响数据库系统的操作,影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失。因此当发生上述故…

logistic回归的标准化回归系数 计算方式

创建于&#xff1a;2022.12.17 修改于&#xff1a;2022.12.17 文章目录1、未标准化回归系数2、标准化回归系数3、两者的区别4、手动计算5、计算样例6、参考资料1、未标准化回归系数 通常我们在构建多因素回归模型时&#xff0c;方程中呈现的是未标准化回归系数&#xff0c;它是…

【财务】财务分析---管理报告体系搭建

财务分析体系搭建的是一个系统化的功能&#xff0c;涉及的业务面非常广&#xff0c;财务分析也能表现出清晰的数据&#xff0c;以此进行改善&#xff1b;本文作者详细分析了财务分析中的管理报告体系的搭建&#xff0c;我们一起来看一下。 一、理清核算、财报、管报、预算关系 …

java设计模式(下)

文章目录第六章 行为型模式(11种)6.1 观察者模式6.1.1 观察者模式介绍6.1.2 观察者模式原理6.1.3 观察者模式实现6.1.4 观察者模式应用实例6.1.5 观察者模式总结6.2 模板方法模式6.2.1 模板方法模式介绍6.2.2 模板方法模式原理6.2.3 模板方法模式实现6.2.4 模板方法模式应用实例…