链表精选题集

news2025/3/1 0:15:49

目录

1 链表翻转

题目链接:

解题:

试错版:

2 找中间节点

题目链接:

题解:

3 找倒数第k个节点

题目链接:

题解:

4 将两个升序链表合并为一个升序链表

题目链接:

题解:

5 给一个值来划分链表再组合

题目链接:

题解:

6 判断链表是否是回文结构

题目链接:

题解:

 7 判断链表是否相交并给出交点

题目链接:

题解:

8 判断链表是否循环

题目链接:

题解:


我们做链表要学会用多指针

1 链表翻转

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

解题:

首先我们假设一个链表里有三个节点:head指向第一个节点(头节点),cur指向第二个节点(需要翻转的节点),curNext指向第三个节点(将要被翻转的节点);

此时cur.next = head就将第二个节点指向了第一个节点,由于第二个节点不指向第三个节点了,因此我们需要有一个curNext来访问第三个节点,防止后面节点丢失;之后将head = cur,这样head就重新指向第一个节点,cur = curNext,这样cur就指向了需要被翻转的节点,curNext = curNext.next,就将curNext指向了下一个被翻转节点。以此类推就可以实现链表翻转。

细节处理:我们完成了一般任务后就要考虑细节

1 当链表为空或者只有一个节点的时候就必独立写出来,因为此时curNext =  head.next.next会出现空指针异常;

2 代码倒数第二行,是将末尾指针的指向设为空,因为如果不设为空,链表就会出现循环;

注意:一个节点的next设置值(改变指向)或者null时一定要注意,因为链表是一连串的,假如我们将第二个节点的指向设置为空,此时如果没有指针指向第三个节点时,那么第三个节点和其后的都将丢失

试错版:

如果自己独立实现过头节点插入的伙伴一定首先想到的是这种方法:

即另外实例化一个链表,然后利用头插法,将原链表中的节点利用头插法依次插入到这个链表中,但是当我们运行后就会发现,最后得到的只有一个节点。

我们来分析一下原因:

上面说过,如果改变某一个节点的指向时,那么这个节点之后的可能就会丢失。我们看上图的代码:用cur依次取出原有链表中的节点,然后插入到新链表中,当插入的时候其中有一个node.next = head,这句话的意思是将cur节点指向head,注意head此时是新链表的head(如果不明白,那么在head前加个this就懂了,谁调用这个方法那么this就代表谁),这个时候cur就指向了空,因为此时没有指针指向cur后面的节点,因此cur后面的节点就都丢失了。所以最后新旧链表都只剩下了第一个节点了;

注意:无论复制多少份链表,都是同一份链表,只要其中一个改变那么全部都会变。

2 找中间节点

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题解:

这种题方法很简单理解后就很容易记住了:

我们找中间数用的是双指针法:即有一个快指针和慢指针,快指针每次走两步,慢的每次走一步,通过简单分析,这里我们要分偶数个还是奇数个节点,此时循环的结束条件也就不一样。当节点偶数个时,那快指针为Null的时候,慢指针才能满足条件;当节点为奇数的时候,只需要在快指针的next(指向)为null时即可满足条件。注意这两个条件的先后,要先确保fast不为空,才能确保fast.next不会出现空指针异常。

最后讨论特殊情况即可。

3 找倒数第k个节点

题目链接:

链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)

public class Solution {
    public ListNode FindKthToTail(ListNode head, int k) {
        if(k<=0 || head == null) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (k > 1) {
           
            fast = fast.next;
             if (fast == null) {
                return null;
            }
            k--;
        }
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;

    }
}

题解:

这道题仍然用双指针。

一般思路是知道这个链表的节点个数,然后再通过循环找到倒数的节点。如果我们只用指针的话就无法得知节点个数,此时就需要解决两个问题,第一个如何判断k是否越界,第二个找到倒数第k个数。

我们的思路是有两个指针,当快指针走到最后一个节点的时候,我们发现所求节点离最后一个节点k-1步,这样我们就可以用快指针来当循环结束条件,当快指针指向最后一个节点的时候停止循环,此时假设慢指针指向所需求的节点,那么返回慢指针即可。那接下来我们怎么才能让循环停止的时候让慢指针指向所求节点,分析很容易得知,让快慢指针均指向头节点,快指针先走k-1步再一起走就可以了。

接下来是判断越界问题,如果k<=0那么直接返回null即可,但是当k大于节点个数的时候怎么办,仔细思考就会发现当我们让快指针走k-1步的时候就可以设置条件来判断k是否越界。

细节:在快指针先走的循环里,我们要先让fast = fast.next再去判断fast是否为null,因为如果先判断的话,这样就会导致循环结束fast正好为空,那么进入下一个循环判断fast.next的时候就会出现空指针异常,而且,我们在最先判断head不为null,也就确保了第一个循环里的fast = fast.next不会出现异常。

4 将两个升序链表合并为一个升序链表

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        int count = 0;
         if(list1 == null) {
            return list2;
        }
        if(list2 == null) {
            return  list1;
        }
        ListNode newhead = new ListNode();
        ListNode cur3 = newhead;
        ListNode cur1 = list1;
        ListNode cur2 = list2;
        while(cur1 != null && cur2 != null) {
            if(cur1.val < cur2.val) {
                if(count == 0) {
                    cur3 = newhead = cur1;
                    count++;
                }else{
                    cur3.next = cur1;
                    cur3 = cur3.next;
                }
                cur1 = cur1.next;

            }else {
                if(count == 0) {
                    cur3 = newhead = cur2;
                    count++;
                }else{
                    cur3.next = cur2;
                    cur3 = cur3.next;

                }
                cur2 = cur2.next;


            }

        }
        if(cur1 == null) {
            cur3.next = cur2;
        }else{
            cur3.next = cur1;
        }
        return newhead;
    }

    }

题解:

这道题思路很常规,定义两个指针,比较并依次插入即可。不多赘述

5 给一个值来划分链表再组合

题目链接:

链表分割_牛客题霸_牛客网 (nowcoder.com)

题解:

public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        if(pHead == null) {
            return null;
        }
        // write code here
        ListNode ss = null;
        ListNode se = null;
        ListNode bs = null;
        ListNode be = null;

        ListNode cur = pHead;
        while (cur != null) {
            if (cur.val < x) {
                if (ss == se && ss == null ) {
                    ss = se = cur;
                } else {
                    se.next = cur;
                    se = cur;
                }
            } else {
                if (bs == be && bs == null ) {
                    bs = be = cur;
                } else {
                    be.next = cur;
                    be = cur;
                }

            }
            cur = cur.next;
        }
        if (se != null ) {
            if(be != null) {
            be.next = null;
            }
            se.next = bs;

            return ss;
        } else {
            return bs;
        }



    }
}

我们的思路是将小于x的节点放一边,大于等于的放另一边,最后让小于一边的最后一个节点去指向另一边的第一个节点。

这部分很简单:定义四个指针,分别指向一边的始尾.

ss指小于x的头节点,se指小于x的尾节点;

bs指大于x的头节点,be指大于x的尾节点;设置尾节点是为了好插入;

细节:

首先就是要考虑链表是否为空,是的话直接返回null;

再者我们要考虑如果节点均大于x的话,那么直接返回bs即可;

最隐匿的一个细节是,最后得到的链表它的尾部是否为null,如果不是就会循环,因此我们最后要手动置空,在置空的时候要判断be是否为空防止空指针。

6 判断链表是否是回文结构

题目链接:

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

题解:

public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
        // write code here
        if (A == null) {
            return false;
        }
        if (A.next == null) {
            return true;
        }
        ListNode fast = A;
        ListNode slow = A;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode cur = slow.next;

        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
            if (curNext != null) {
                curNext = curNext.next;
            }
        }
       ListNode start = A;
        while (start != null && slow != null) {
            if (start.val != slow.val) {
                return false;
            }
            if (start == slow || start.next == slow) {
                return true;
            }
            start = start.next;
            slow = slow.next;
        }
        return false;


    }
}

这道题是道综合题,方法都讲过,现在我们来看一下这道题思路:

判断是否回文,我们可以设置一个始尾指针,通过一个个比较进行判断;首先要想这么做那么我们必须翻转链表中间以后节点的指向,而找到中间节点又可以通过上面讲的快慢指针来寻找;

第一个循环是为了找到中间节点,将这个节点的指针设置为slow,而后设置两个cur和curNext来指向需要翻转和将要反转的指针;注意这个循环的结束条件不能是slow.next == null;(因为此时最后一个节点指向的是前一个节点,而不是Null) ;最后一步就是设置始尾指针来进行判断。注意这个循环的判断条件,当节点总数是奇数的时候,两个指针会相遇,那么当slow == start的时候可以结束循环,但是节点总数是偶数的时候判断起来就有一点难度,这个时候当我们画图可以知道,如果start.next == slow时,就可以结束循环。

其他情况:当链表为null或者只有一个节点的时候直接返回。

 7 判断链表是否相交并给出交点

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题解:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int l = 0;
        int s = 0;
        ListNode cur = headA;
        while(cur != null) {
            l++;
            cur = cur.next;
        }
        cur = headB;
        while (cur != null) {
            s++;
            cur = cur.next;
        }
        ListNode lNode = headA;
        ListNode sNode = headB;
        if(l - s < 0) {
            int tem = s;
            s = l;
            l = tem;
            lNode = headB;
            sNode = headA;
        }
        int result =l - s;
        while(result > 0) {

            lNode = lNode.next;
            result--;
        }
        while(lNode != null && sNode != null ) {
            if(lNode == sNode){
                return lNode;
            }
            lNode = lNode.next;
            sNode = sNode.next;

        }
        return null;
        
    }
}

这道题就按常规思路来解题,我们要想判断两个链表是否相交,那我们就要看他们是否有相同的节点,如果有的话,那么这个节点及其以后的都一样,只是这个节点前的部分不一样,假设有个指针指向节点A,另一个指针指向节点B,如果两个链表相同节点前部分长度相同,那么只需要A,B走相同步数就可以走到相同节点,但是如果长度不一样差了n步,那么我们就可以先让长的链表先走n步,之后两个链表再一起走,如果A==B那么说明两个链表相交,否则不相交。

解释代码:

首先我们定义了l和s,来记录两个链表各自的长度,之后设置两个指针来分别指向A,B的头节点,为了确保lNode指向长链表的头结点,sNode指向短的,我们在中间加了一个if条件;之后设置一个循环让长链表的指针走n步,走完后;再设置一个循环,让长短指针一起走,能相遇返回节点,不能返回null.

8 判断链表是否循环

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题解:

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null) {
            
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) {
                return true;
            }
        }
        return false;
        
    }
}

这道题思路有点难:

如果链表不是循环那么,判断很简单,让指针不断指向下一个那么迟早会穷尽,但是如果链表循环,那么这样子就不行了,遇到链表问题没办法时可以从多指针下手,就容易拨云见日;

我们设置了两个指针,在一个圈内,不论时间,一个速度快的人总是能够追赶上一个速度慢的,同理在一个成环的链表里,快指针迟早会追赶上慢指针,这就是我们的思路。

解释代码:

我们设置了一个快指针和慢指针,设置循环,让快指针走两步,慢指针走一步,相遇返回true,不相遇那么循环迟早结束,返回null.

思考:为什么非要快指针走两步,慢指针走一步;这是个数学问题,大家可以想一下;

感兴趣的可一看一下:

进阶问题:找到循环的入口点(数学问题,解方程);

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

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

相关文章

[电磁学]猴博士不挂科

1 利用表格求场强 2 利用叠加求场强 3 利用积分求场强 电场立库仑力 球的面积公式是4πr&#xff0c;其中r为球的半径。 球的体积公式是(4/3)πr&#xff0c;其中r为球的半径。 带电物体有体积:

软件测试/测试开发丨Python 内置库 OS 学习笔记分享

os 概述 os: Operating System os 使用 导入 os 模块 查看 os 模块使用文档 help(os)dir(os) import os# 查看os模块说明文档 help(os)# 查看os模块的属性和方法 print(dir(os))os 操作系统相关 os.name&#xff1a;获取系统名称os.environ&#xff1a;获取系统环境变量信…

是时候将javax替换为Jakarta了

开始 相信很多朋友在使用新版本的Spring的时候&#xff0c;发现了一些叫jakarta的包&#xff0c;看起来有点陌生。 很多时候&#xff0c;比较纠结不知道该导入哪一个包。 jakarta其实就是之前的javax。 主要JavaEE相关的&#xff0c;从之前javax名字也可以看出来&#xff0…

【AMD Xilinx】ZUBoard(2):通过AXI GPIO控制PL端的管脚输出

【AMD Xilinx】ZUBoard&#xff08;2&#xff09;&#xff1a;通过AXI GPIO控制PL端的管脚输出 一、基本功能和流程二、Vivado工程1. 总体框图2. AXI GPIO相关部分3. 配置AXI GPIO4. 绑定管脚4.1 根据原理图查找对应管脚4.1.1 LED04.1.2 LED1 4.2 I/O Planning 5. XDC 三、ARM代…

python+django游戏分享论坛网站49c2c

本系统主要包括管理员和用户两个角色组成&#xff1b;主要包括首页、个人中心、用户管理、游戏类型管理、游戏文章管理、交流论坛、系统管理等功能的管理系统。 系统权限按管理员和用户两类涉及用户划分。 &#xff08;1&#xff09;管理员功能需求 管理员登陆后&#xff0c;主…

c++学习笔记-提高篇-STL-函数对象

目录 一、函数对象 二、函数对象使用 三、谓词 1、概念 2、一元谓词 3、二元谓词 插入一条sort函数源码 四、内建函数对象 1.基本概念 2、算数仿函数 3、关系仿函数 4、逻辑仿函数 一、函数对象 函数对象概念 &#xff08;1&#xff09;重载函数调用操作符的类&a…

ESP32:整合存储配网信息和MQTT笔记

文章目录 1.给LED和KEY的所用IO增加配置项1.1 增加配置文件1.2 修改相应的c源码 2. 把mqtt\tcp的工程整合到一起2.1 在何处调用 mqtt_app_start() 3. 测试MQTT4. 完整的工程源码 有一段时间没有玩ESP32&#xff0c;很多知识点都忘记了。今天测试一下MQTT&#xff0c;做个笔记。…

Vue.js学习笔记(1)——Visual Studio Code搭建Vue.js框架

1 安装Node.js 1、下载安装包&#xff1a;进入官网&#xff08;https://nodejs.org/en&#xff09;&#xff0c;下载左侧的稳定版。 2、选择安装位置&#xff0c;不用勾选自动安装必要工具。 其他都默认Next。 配置环境&#xff0c;具体参考本文章&#xff1a; https://blo…

数据结构之树 --- 二叉树 < 堆 >

目录 1. 树是什么&#xff1f; 1.1 树的表示 2. 二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储结构 2.4.1 顺序存储 2.4.2 链式存储 3. 二叉树顺序结构的实现 <堆> 3.1 二叉树的顺序结构 ​编辑 3.2 堆的概念及结构 ​编辑…

啊?这也算事务?!

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

数据库开发之事务和索引的详细解析

2. 事务 场景&#xff1a;学工部整个部门解散了&#xff0c;该部门及部门下的员工都需要删除了。 操作&#xff1a; -- 删除学工部 delete from dept where id 1; -- 删除成功 ​ -- 删除学工部的员工 delete from emp where dept_id 1; -- 删除失败&#xff08;操作过程中…

Linux升级指南:保持系统安全和高效运行

Linux系统的升级是确保系统稳定和安全性的重要步骤。本文将介绍Linux系统升级的基本概念&#xff0c;以及具体的操作步骤和注意事项&#xff0c;以帮助用户顺利升级他们的Linux系统。 Linux操作系统以其稳定性和可定制性而闻名&#xff0c;它经常通过升级来提供新的功能、修复漏…

C++ 之LeetCode刷题记录(五)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅&#xff0c;多学多练&#xff0c;尽力而为。 先易后难&#xff0c;先刷简单的。 20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&…

[GDOUCTF 2023]hate eat snake

[GDOUCTF 2023]hate eat snake wp 一般说玩游戏的题答案在源码里&#xff0c;但是本题源码中没有任何跟 “flag” 或者 “ctf” 有关的信息。 页面如下&#xff1a; 唤出控制台 在此页面中 F12 调不出控制台&#xff08;可能是在 js 代码中禁用了&#xff09;。但其实还有两…

结构体:是第几天

今天是该年的第几天 #include<iostream> using namespace std; struct Date //创建结构体 {int year; //年int month; //月int day; //日 }; void inputDate(Date *p) //输入函数 {cin >> p->year >> p->month >> p->day; //输入年、月、…

使用Google OSV工具扫描依赖安全漏洞

安全漏洞是软件工程化能力的试金石 2021年年底&#xff0c;Log4j的漏洞陆续被公开。因为该框架被大量的开源软件依赖&#xff0c;所以&#xff0c;漏洞影响面非常大。 面对这个漏洞&#xff0c;我们遇到的第一个问题是&#xff1a;如何知道我们哪些工程使用了Log4j&#xff1f;…

如何修改Anaconda的Jupyter notebook的默认启动路径

1.打开Anaconda控制台 2.输入下面的命令 jupyter notebook --generate-config 这个命令的作用是生成 Jupyter notebook 的配置文件。如果你是第一次运行&#xff0c;会直接生成这个文件。如果曾经运行过这个命令&#xff0c;就会像下图一样问你时候要覆盖原来的文件。这个时候…

几种取时间的方法(附代码)

1.上古版 最原始的取时间的方法大概就是timelocaltime了&#xff0c;见代码&#xff1a; #include <stdio.h>#include <time.h>// gcc -o time_1 time_1.cint main(){time_t tm_now;time(&tm_now);// 或者写成 tm_now time(NULL);//1.直接打印&#xff1a;197…

探讨kernel32.dll文件是什么,有效解决kernel32.dll丢失

在使用电脑时&#xff0c;你是否遇到过kernel32.dll丢失的困扰&#xff1f;面对这个问题&#xff0c;我们需要及时去解决kernel32.dll丢失的问题。接下来&#xff0c;我们将深入探讨kernel32.dll的功能以及其在操作系统和应用程序中的具体应用领域&#xff0c;相信这将对你解决…

鸿蒙HarmonyOS-带笔锋手写板(三)

笔者用ArkTS 写了一个简单的带笔锋的手写板应用&#xff0c;并且可以将手写内容保存为图片。 一、效果图 手写效果如下&#xff08;在鸿蒙手机模拟器上运行&#xff0c;手写时反应可能会有点慢&#xff09; 二、实现方法 参考文章&#xff1a; 支持笔锋效果的手写签字控件_a…