【数据结构(四)】链表经典练习题

❣博主主页: 33的博客❣
▶️文章专栏分类:数据结构◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你学更多数据结构知识

在这里插入图片描述

目录

  • 1.前言
  • 2.删除值为key的所有结点
  • 3.反转链表
  • 4.返回中间结点
  • 5.输出倒数第k个结点
  • 6.链表分割
  • 7.链表回文
  • 8.相交链表
  • 9.环形链表
    • 9.1是否为环形链表
    • 9.2入环第一个节点
  • 10.总结

1.前言

在上一篇文章中博主已经介绍了链表的基础知识,什么是链表,如何实现一个链表,以及LinkedList的操作方法,那么在这篇文章中通过一些链表的经典习题来练习吧。

2.删除值为key的所有结点

删除值为val的所有结点:OJ链接
解题思路:

1.遍历链表。
2.如果某个结点A的值等于key,那么A的前一个结点B的next值直接等于A的next。
3,继续遍历,遇到等于值等于key的重复上诉操作,直到全部遍历完成。

public void removeAllKey(int key) {
    if (head==null){
        return;
    }
    Node node=head;
    Node cur=head.next;
    while (cur!=null){
        if(cur.val==key){
            node.next=cur.next;
            cur=cur.next;
        }else {
            node=node.next;
            cur=cur.next;
        }
    }
    if(head.val==key){
        head=head.next;
    }
    }

3.反转链表

反转链表:OJ链接

public ListNode reverseList(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode cur=head.next;
        head.next=null;
        while (cur!=null){
            ListNode curNext=cur.next;
            cur.next=head;
            head=cur;
            cur=curNext;
        }
        return head;
    }

4.返回中间结点

返回中间结点:OJ链接
方式一:
解题思路:

1.求链表的大小size
2.中间结点为size/2
遍历链表,走到size/2的位置,返回该节点

class Solution {
	//求链表长度
    public int size(ListNode head) {
        ListNode node=head;
        int count=0;
        while (node!=null){
           count++;
            node=node.next;
        }
        return count;
    }
    public ListNode middleNode(ListNode  head) {
        if(head==null||head.next==null){
            return head;
        }
        int Size=size(head);
        int middle=Size/2;
        ListNode node=head;
        for (int i=0;i<middle;i++){
            node=node.next;
        }
        return node;
    }    
}

方式二:
解题思路:

1.设置一个快结点:fast,设置一个慢结点:slow。
2.我们试想:如果fast的速度是slow的两倍,那么当fast到达路程的终点时,此时slow就走了路程的一半。
3.所以我们让fast每次走两步,slow每次走一步,当fast=null或者fast.next=null的时候,slow就是中间结点

public Node middleNode2() {
        Node fast=head;
        Node slow=head;
        while (fast!=null||fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        return slow;
    }

5.输出倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点:OJ链接
解题思路:

1。让fast先走k-1步数
2.再同时走,当fast到达终点时,那么它们就相差k
3.此时的slow就是倒数第k个结点

ublic Node FindKthToTail (int k) {
        Node fast=head;
        Node slow=head;
    if(k<=0||head==null){
        return null;
    }
    while (k-1>0){
        fast=fast.next;
        k--;
    }
    while (fast.next!=null){
        fast=fast.next;
        slow=slow.next;
    }
    return slow;
    }

6.链表分割

以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前:OJ链接
解题思路:

1.首先,遍历链表
2.再创建两个链表,一个用于存放小于x的值,另一个用于存放大于x的值
3.再把第一个链表的最后一个结点与第二个链表的头节点串起来。

public Node partition(int x) {
        if (head==null){
            return null;
        }
        Node as=null;
        Node ae=null;
        Node bs=null;
        Node be=null;
        Node cur=head;
        while (cur!=null){
            if (cur.val<x){
              if(as==null){
                  //插入第一个节点
                  as=cur;
                  ae=cur;
                  cur=cur.next;
              } else {
                  ae.next=cur;
                  ae=ae.next;
                  cur=cur.next;
              }
            }else {
             //cur.val>x
             if(bs==null){
             //插入第一个节点
                 bs=cur;
                 be=cur;
                 cur=cur.next;
             }  else {
                 be.next=cur;
                 be=be.next;
                 cur=cur.next;
             }
            }
        }
        //如果第一个链表为空就直接返回第二个链表的头节点
        if(as==null){
            return bs;
        }
        ae.next=bs;
        if(bs != null) {
            //第2个区间有数据
            be.next = null;
        }
        head=as;
        return head;
    }

7.链表回文

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构:OJ链接
解题思路:

1.查看链表是否回文,是指从前向后遍历,或者从后向前遍历,输出的之都相同。
2.我们可以先找到中间位置,再从中间位置进行翻转,使它同时从两头向中间遍历
3.遍历的时候如果如果链表有偶数个的情况,和有奇数个的情况是不一样的,当有奇数个时,走到相同的位置就停止,当有偶数个时,当下再走一步就相遇时就停止。

public boolean chkPalindrome() {
		 if(head == null || head.next == null) {
            return true;
        }
        //按照中间位置翻转链表
        //1.找到中间位置(middle已经在4中写过)
        Node middle=middleNode2();
        //2.翻转
        Node ehead=middle;
        Node cur=ehead.next;
        while (cur!=null){
            Node curNext=cur.next;
            cur.next=ehead;
            ehead=cur;
            cur=curNext;
        }
        //从两头开始遍历
        Node snode=head;
        Node enode=ehead;
        while (snode!=enode){
            if (snode.val!=enode.val){
                return false;
            }
            if (snode.next==enode){
                return true;
            }
                snode=snode.next;
                enode=enode.next;
        }
        return true;
    }

8.相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点:OJ链接
解题思路:

1.求两个链表的长度,再求长度差值
2.定义节点fast代表长的链表头节点,slow代表短的链表的头节点。先让长的链表先走差值步,再同时走。
3.两个链表相遇时就是相交节点。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {        
        ListNode nodeA=headA;
        ListNode nodeB=headB;
        int lenA=size(headA);
        int lenB=size(headB);
        ListNode fast=headA;
        ListNode slow=headB;
        int len=lenA-lenB;
        if(len<0){
            len=lenB-lenA;
            fast=headB;
            slow=headA;
        }
        while(len>0){
            fast=fast.next;
            len--;
        }
        while(fast!=slow&&fast!=null){
            fast=fast.next;
            slow=slow.next;
        }       
        return fast;      
    }

9.环形链表

9.1是否为环形链表

给你一个链表的头节点 head ,判断链表中是否有环:OJ链接
解题思路:

1.定义节点fast代表长的链表头节点,slow代表短的链表的头节点.
2.每次让fast走两步,slow走一步,如果是环形链表,那么它们一定会在环中的某一个位置相遇,否则不是环形链表
为什么每次让fast走两步,slow走一步?不可以fast走3步,4步吗?假设环中只有两个元素A,B,当slow进入环时在A的节点的位置,此时fast在B节点的位置,slow走一步就到B的位置,fast走3步就到A的位置,那么它们永远都不会相遇。
只有每次让fast走两步,slow走一步,换的长度为1,那么肯定会相遇。

 public boolean hasCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            //fast.next!=null&&fast!=null,不能这样写
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                return true;
            }   
        }
        return false;       
    }

9.2入环第一个节点

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null:OJ链接
解题思路:

让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
证明如下:

在这里插入图片描述

public class Solution {
    ListNode hasCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            //fast.next!=null&&fast!=null,不能这样写
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                return fast;
            }   
        }
        return null;       
    }
    public ListNode detectCycle(ListNode head) {
          ListNode fast=hasCycle(head);
          if(fast==null){
            return null;
          }
          ListNode slow=head;
          while(fast!=slow){
            fast=fast.next;
            slow=slow.next;
          }
          return fast;  
    }
}

10.总结

本篇博客主要对链表的经典习题进行了讲解,同学们要理解解题的一些思想做到融会贯通,如果有疑惑的地方欢迎大家来和博主沟通,交流。

下期预告:栈

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024-04-10 Linux gzip 和 gunzip 命令,gzip 压缩的文件通常比原始文件小得多。

一、gzip 是 Linux 系统中用于压缩文件的命令&#xff0c;它通常用于将单个文件压缩成 .gz 格式的文件。gzip 压缩的文件通常比原始文件小得多&#xff0c;因此它在节省磁盘空间和减少文件传输时间方面非常有用。 gzip 命令的基本语法如下&#xff1a; gzip [选项] [文件]复制…

VMware vSphere Hypervisor,ESXi的介绍,下载与安装

1.介绍 看这篇文章就好了 Vmware ESXi 是免费吗&#xff1f;一文弄懂vSphere功能特性及ESXi与vSphere到底有什么区别和联系。 - 知乎 (zhihu.com) 2.下载 这里面有7.0各个版本的下载镜像文件和校验信息 VMware-Esxi7.0各个版本镜像文件iso下载链接_esxi7.0镜像-CSDN博客 3.…

团结引擎+OpenHarmony 2 xlua编译篇

文章目录 前言一、下载 xlua 源码二、OpenHarmony SDK三、开干 前言 提示&#xff1a;我们的 app 鸿蒙化过程 需要用到 xlua ,目前没有适配 OpenHarmony 平台&#xff0c;所以需要重新编译一下。编译有多种方式&#xff0c;但是我只会这一种 就是使用 cmake。 一、下载 xlua 源…

花一分钟简单认识 CSS 中的规则 —— 级联层 @layer

layer 简介&#xff1a; 声明级联层时&#xff0c;越靠后优先级越高。不属于任何级联层的样式&#xff0c;将自成一层匿名级联层&#xff0c;并置于所有层之后 —— 级别最高。 用法一&#xff1a;在同一文件中 layer base, special; layer special {/* 优先 */li { color: …

2、Qt UI控件 -- qucsdk项目使用

前言&#xff1a;上一篇文章讲了qucsdk的环境部署&#xff0c;可以在QDesigner和Qt Creator中看到qucsdk控件&#xff0c;这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库&#xff0c;需要三个先决条件&#xff0c; 1、控件的头文件 2、动/静态链…

软考数据库---1.事务管理

目录 1.1 事物的基本概念1.2 数据库的并发控制1.2.1 事务调度概念1.2.2 并发操作带来的问题1.2.3 并发控制技术1.2.4 隔离级别&#xff1a; 1.3 数据库的备份和恢复1.3.1 故障种类1.3.2 备份方法1.3.3 日志文件1.3.4 恢复 1.1 事物的基本概念 ●概念&#xff1a;一个操作序列&…

AiChat是什么?

AIChat是一款功能强大的聚合AI大模型智能聊天助手&#xff0c;为用户提供自动化的客服和聊天机器人服务。无论是需要为企业提供更好的客户体验&#xff0c;还是为个人用户提供高效便捷的服务&#xff0c;AIChat都是最佳选择。本文将详细介绍AIChat的特点和优势。 Aichat简介&am…

学习R语言第二天

R语言可以做什么 1.数据分析 R语言如何使用 1. 请看我的操作方式 2. 如何获取当前路径 -- 获取当前路径 > getwd() [1] "E:/R/RWorkSpace/day01" -- 修改当前路径 > setwd(dir "E:/R") > getwd() [1] "E:/R" 3.查看当下数据值的信…

HCIP课后习题之一

1、路由协议用工作机制上分为那几种&#xff1f;分别是&#xff1f; A&#xff1a;两种。分别是静态路由和动态路由&#xff08;可分为IGP和EGP&#xff09; 2、IGP和EGP协议有哪些&#xff1f; A&#xff1a;IGP: RIP、OSPF、ISIS、EIGRP EGP: BGP 3、路由优先级的用途&…

机器人坐标系转换之从世界坐标系到局部坐标系

三角函数实现 下面是代码c和python实现&#xff1a; #include <iostream> #include <cmath>struct Point {double x;double y; };class RobotCoordinateTransform { private:Point origin; // 局部坐标系的原点在世界坐标系中的坐标public:RobotCoordinateTransfo…

zabbix企业级监控平台

zabbix部署 安装源 重新创建纯净环境&#xff0c;利用base克隆一台虚拟机server1 给server1做快照&#xff0c;方便下次实验恢复使用 进入zabbix官网https://www.zabbix.com rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm …

C++:构造函数、析构函数、拷贝构造函数

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;构造函数、析构函数、拷贝构造函数》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞…

c++的学习之路:16、list(3)

上章有一些东西当时没学到&#xff0c;这里学到了将在补充&#xff0c;文章末附上代码&#xff0c;思维导图。 目录 一、赋值重载 二、带模板的创建 三、析构函数 四、代码 五、思维导图 一、赋值重载 这里的赋值重载就是直接利用交换函数进行把传参生成的临时数据和需要…

Vue 读取后台二进制文件流转为图片显示

Vue 读取后台二进制文件流转为图片显示 后台返回格式 <img :src"payImg" id"image" style"width: 150px;height: 150px;" alt"">axios写法 重点 responseType: ‘blob’ &#xff0c; 使用的是res中的data blob this.$axios.…

Linux之线程互斥与同步

1.线程互斥相关概念 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源 。 临界区&#xff1a;每个线程内部&#xff0c;访问临界自娱的代码&#xff0c;就叫做临界区。 互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临界区&#xff0c;访问临…

【Locust分布式压力测试】

Locust分布式压力测试 https://docs.locust.io/en/stable/running-distributed.html Distributed load generation A single process running Locust can simulate a reasonably high throughput. For a simple test plan and small payloads it can make more than a thousan…

Ubuntu-22.04安装VMware虚拟机并安装Windows10

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、VMware是什么&#xff1f;二、安装VMware1.注册VMware账号2.下载虚拟机3.编译vmmon&vmnet4.加载module5.安装bundle 三、安装Windows101.基础配置2.进阶…

Java基础_15集合及其方法

今天的内容 1.集合 1.集合【重点】 1.1为什么使用集合 集合和数组是一样的都是用来存储数据的&#xff01;&#xff01;&#xff01; 真实的开发的时候&#xff0c;使用的是集合不是数组&#xff0c;为啥&#xff1f; 数组存数据: ​ 1.数组的容量是固定的 ​ 2.数组封装的方法…

Dude, where’s that IP? Circumventing measurement-based IP geolocation(2010年)

下载地址:https://www.usenix.org/legacy/event/sec10/tech/full_papers/Gill.pdf 被引次数:102 Gill P, Ganjali Y, Wong B. Dude, Wheres That {IP}? Circumventing Measurement-based {IP} Geolocation[C]//19th USENIX Security Symposium (USENIX Security 10). 2010.…

基于springboot实现常州地方旅游管理系统项目【项目源码+论文说明】

基于springboot实现旅游管理系统演示 摘要 随着旅游业的迅速发展&#xff0c;传统的旅游信息查询方式&#xff0c;已经无法满足用户需求&#xff0c;因此&#xff0c;结合计算机技术的优势和普及&#xff0c;针对常州旅游&#xff0c;特开发了本基于Bootstrap的常州地方旅游管…