数据结构(Java版)第八期:LinkedList与链表(三)

news2025/1/16 1:58:13

专栏:数据结构(Java版)

个人主页:手握风云

目录

一、链表中的经典面试题

1.1. 链表分割

1.2. 链表的回文结构

1.3. 相交链表

1.4. 环形链表


一、链表中的经典面试题

1.1. 链表分割

        题目中要求不能改变原来的数据顺序,也就是如上图所示。我们先定义一个cur引用去遍历这个链表,用每个结点的val值与x进行比较,然后利用尾插的方法把结点插入进两个链表中。我们先定义bs、be、as、ae四个引用来表示两个链表的头尾,在尾插的时候需要注意,利用ae.next = node;ae = node,记录下尾结点,保证ae永远指向最后一个结点,同时be.next=as,连接上两个链表。

class ListNode{
    int val;
    ListNode next = null;

    public ListNode(int val) {
        this.val = val;
    }
}

public class Partition {
    public ListNode partition(ListNode pHead, int x){
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;

        ListNode cur = pHead;
        while(cur != null){
            if(cur.val < x){

            }else{

            }
        }
    }
}

        代码的大体框架已经写好,这时我们需要考虑一下当第一段插入第一个节点时,第一个节点既是头又是尾。这时有需要分两种情况,第一次插入与下一次插入,来移动be引用。

        while(cur != null){
            if(cur.val < x){
                //第一次插入
                if(bs == null){
                    be = bs = cur;
                }else {
                    be.next = cur;
                    be = cur;
                }
            }else{
                //第一次插入
                if(as == null){
                    ae = as = cur;
                }else {
                    ae.next = cur;
                    ae = cur;
                }
            }
            cur = cur.next;

       这时的代码还存在一种我们没有想到的情况,如果给定的测试用例都大于x的值呢。这是我们就需要返回as。我们还需要分情况。

        if(bs == null){
            return as;
        }

       如果这是我们放到OJ进行测试,发现报出异常。

        这个异常的原因比较隐蔽。因为bs为空,尾节点ae会返回bs,如果ae之前的地址指向之前的某个节点,就会造成链表的死循环,此时我们要将排列之后的链表最后一个节点手动置为null。

完整代码: 

class ListNode{
    int val;
    ListNode next = null;

    public ListNode(int val) {
        this.val = val;
    }
}

public class Partition {
    public ListNode partition(ListNode pHead, int x){
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;

        ListNode cur = pHead;
        while(cur != null){
            if(cur.val < x){
                //第一次插入
                if(bs == null){
                    be = bs = cur;
                }else {
                    be.next = cur;
                    be = cur;
                }
            }else{
                //第一次插入
                if(as == null){
                    ae = as = cur;
                }else {
                    ae.next = cur;
                    ae = cur;
                }
            }
            cur = cur.next;
        }
        if(bs == null){
            return as;
        }
        be.next = as;//连接上两个链表
        if(as != null){
            ae.next = null;
        }
        return bs;
    }
}

1.2. 链表的回文结构

       第一种思路,我们可以使用双引用算法,一个left引用从左开始向右移动,另一个right引用从右开始向左移动。但由于这个链表是单链表,只能从一个方向遍历。

       第二种思路,把链表里的val值取出,存进一个数组中,但题目要求空间复杂度为O(n) 。

       第三种思路,翻转一半的链表。过程分为三步,第一步,找到链表的中间部分;第二步,将链表的一半进行翻转。我们在上一期中,已经实现了翻转链表和寻找链表的中间节点。

while(cur != null){
    curN = cur.next;
    cur.next = slow;
    slow = cur;
    cur = curN;
}

        利用上面的代码我们就可以来翻转链表,第三步,head从前往后,slow从后往前,比较head.val是否与slow.val相等,直到slow引用与头节点相遇为止。这里我们讨论的是奇数个节点的链表,如果是有偶数个节点的链表,那么fast为空。

       当链表的节点为偶数时,我们不能按照之前的做法,当head.next = slow时,直接返回true。

完整代码:

import java.util.Scanner;

class ListNode{
    int val;
    ListNode next;

    public ListNode(int val) {
        this.val = val;
    }
}

public class PalindromeList {
    public boolean chkPalindrome(ListNode A){
        //1、找到链表的中间节点
        ListNode fast = A;
        ListNode slow = A;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        //2、反转链表
        ListNode cur = slow.next;
        while(cur != null){
            ListNode curN = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curN;
        }
        //3、引用A与slow同时移动
        while(A != slow){
            if(A.val != slow.val){
                return false;
            }
            //判断偶数个节点情况
            if(A.next == slow){
                return true;
            }
            A = A.next;
            slow = slow.next;
        }
        return true;
    }
}

1.3. 相交链表

       对于链表相交的问题,我们首先要考虑明白,到底是X形相交,还是Y形相交?

       如上图所示,很明显两个链表相交之后呈Y形。要解决问题,我们同样利用双引用的算法。第一步,先求出两个链表的长度len1、len2;第二步求出两个链表的长度差len=len1-len2;第三步,让长的链表先走len步;第四步,headA与headA同时走,相遇之后就是公共交节点。

      这个题的思路其实很简单,但是其中也有一些比较麻烦的步骤。在第二步中,如果说len1<len2,那么len<0。第三步中,我们又怎么知道哪个链表更长?

class ListNode{
    int val;
    ListNode next;
    ListNode(int x){
        val = x;
        next = null;
    }
}

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB){
        ListNode pl = headA;//先假设链表A是长的
        ListNode ps = headB;

        //求两个链表的长度
        int len1 = 0,len2 = 0;
        while(pl != null){
            len1++;
            pl = pl.next;
        }
        while(ps != null){
            len2++;
            ps = ps.next;
        }
        pl = headA;
        ps = headB;

        //求链表的长度差
        int len = len1 - len2;
        if(len < 0){
            pl = headB;
            ps = headA;
            len = len2-len1;
        }

        //让pl先走len步
        while(len != 0){
            pl = pl.next;
            len--;
        }

        //pl与ps同时走,知道相遇。
        while(pl != ps){
            pl = pl.next;
            ps = ps.next;
        }
        //如果没有公共节点,直接返回null
        if(pl == null){
            return null;
        }
        return pl;
    }
}

1.4. 环形链表

        快慢引用,即慢引用⼀次⾛⼀步,快引用⼀次⾛两步,两个引用从链表起始位置开始运⾏,如果链表带环则⼀定会在环中相遇,否则快引用率先⾛到链表的末尾。与现实生活中不同,两人相遇有可能是擦肩而过。而引用确实一步一步走的。

        为什么要让快引用走两步,慢引用走一步呢?我们想象一种最极限的情况,当fast刚走完一圈时,slow刚进入环内,两个引用的距离差刚好是一个环的距离。当fast与slow每走一次,它们的距离就越接近一个环。

class ListNode{
    int val;
    ListNode next;
    ListNode(int x){
        val = x;
        next = null;
    }
}

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;
    }
}

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

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

相关文章

flutter R库对图片资源进行自动管理

项目中对资源的使用是开发过程中再常见不过的一环。 一般我们在将资源导入到项目中后&#xff0c;会通过资源名称来访问。 但在很多情况下由于我们疏忽输入错了资源名称&#xff0c;从而导致资源无法访问。 所以&#xff0c;急需解决两个问题&#xff1a; 资源编译期可检查可方…

doc、pdf转markdown

国外的一个网站可以&#xff1a; Convert A File Word, PDF, JPG Online 这个网站免费的&#xff0c;算是非常厚道了&#xff0c;但是大文件上传多了之后会扛不住 国内的一个网站也不错&#xff1a; TextIn-AI智能文档处理-图像处理技术-大模型加速器-在线免费体验 https://…

计算机网络 (41)文件传送协议

前言 一、文件传送协议&#xff08;FTP&#xff09; 概述&#xff1a; FTP&#xff08;File Transfer Protocol&#xff09;是互联网上使用得最广泛的文件传送协议。FTP提供交互式的访问&#xff0c;允许客户指明文件的类型与格式&#xff08;如指明是否使用ASCII码&#xff0…

软件测试 —— 自动化测试(Selenium)

软件测试 —— 自动化测试&#xff08;Selenium&#xff09; 什么是SeleniumPython安装Selenium1.安装webdirver-manager2.安装Selenium 写一个简单用例CSS_SELECTOR和XPATH浏览器快速定位页面元素浏览器的前进&#xff08;forward&#xff09;&#xff0c;后退&#xff08;bac…

python识别图片中指定颜色的图案并保存为图片

示例代码&#xff1a; def chuli(color):import cv2import numpy as np# 定义颜色名称到HSV阈值范围的映射color_thresholds {red: ([0, 100, 100], [10, 255, 255], [160, 100, 100], [180, 255, 255]),yellow: ([20, 100, 100], [30, 255, 255]),blue: ([90, 100, 100], [1…

流浪猫流浪狗领养PHP网站源码

源码介绍 流浪猫流浪狗领养PHP网站源码&#xff0c;适合做猫狗宠物类的发信息发布。当然其他信息发布也是可以的。 导入数据库&#xff0c;修改数据库配置/application/database.php 设置TP伪静态&#xff0c;设置运行目录&#xff0c; 后台&#xff1a;/abcd.php/dashboard?…

Chatper 4: Implementing a GPT model from Scratch To Generate Text

文章目录 4 Implementing a GPT model from Scratch To Generate Text4.1 Coding an LLM architecture4.2 Normalizing activations with layer normalization4.3 Implementing a feed forward network with GELU activations4.4 Adding shortcut connections4.5 Connecting at…

Linux:Makefile 以及实现第一个程序:进度条

1.Makefile初认识 &#xff08;1&#xff09;Makefile内部结构的基本认识 &#xff08;2&#xff09;开始使用宏替换的进阶版本 &#xff08;3&#xff09;多文件的最终版本 BIN:可执行程序的别名 SRC $(wildcart *.c):表示所有.c文件 OBJ $(SRC: .c .o):表示SRC下的所有.c…

Golang笔记——Interface类型

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Golang的interface数据结构类型&#xff0c;包括基本实现和使用等。 文章目录 Go 语言中的 interface 详解接口定义实现接口空接口 interface{}示…

HBuilderX打包ios保姆式教程

1、登录苹果开发者后台并登录已认证开发者账号ID Sign In - Apple 2、创建标识符&#xff08;App ID&#xff09;、证书&#xff0c;描述文件 3、首先创建标识符&#xff0c;用于新建App应用 3-1、App的话直接选择第一个App IDs&#xff0c;点击右上角继续 3-2、选择App&#x…

【Vue】Vue组件--上

目录 一、组件基础 二、组件的嵌套关系 1. 基础架构 2. 嵌套 三、组件注册方式 1. 局部注册&#xff1a; 2. 全局注册&#xff1a; 四、组件传递数据 1. 基础架构 2. 传递多值 3. 动态传递数据 五、组件传递多种数据类型 1. Number 2. Array 3. Object 六、组…

【Vue3 入门到实战】1. 创建Vue3工程

目录 ​编辑 1. 学习目标 2. 环境准备与初始化 3. 项目文件结构 4. 写一个简单的效果 5. 总结 1. 学习目标 (1) 掌握如何创建vue3项目。 (2) 了解项目中的文件的作用。 (3) 编辑App.vue文件&#xff0c;并写一个简单的效果。 2. 环境准备与初始化 (1) 安装 Node.js 和 …

使用Flink-JDBC将数据同步到Doris

在现代数据分析和处理环境中&#xff0c;数据同步是一个至关重要的环节。Apache Flink和Doris是两个强大的工具&#xff0c;分别用于实时数据处理和大规模并行处理&#xff08;MPP&#xff09;SQL数据库。本文将介绍如何使用Flink-JDBC连接器将数据同步到Doris。 一、背景介绍…

深度学习中的学习率调度器(scheduler)分析并作图查看各方法差异

文章目录 1. 指数衰减调度器&#xff08;Exponential Decay Scheduler&#xff09;工作原理适用场景实现示例 2. 余弦退火调度器&#xff08;Cosine Annealing Scheduler&#xff09;工作原理适用场景实现示例 3. 步长衰减调度器&#xff08;Step Decay Scheduler&#xff09;工…

基于springboot+vue+微信小程序的宠物领养系统

基于springbootvue微信小程序的宠物领养系统 一、介绍 本项目利用SpringBoot、Vue和微信小程序技术&#xff0c;构建了一个宠物领养系统。 本系统的设计分为两个层面&#xff0c;分别为管理层面与用户层面&#xff0c;也就是管理者与用户&#xff0c;管理权限与用户权限是不…

Nginx安全加固系列:Referrer-Policy

假设页面有一个链接&#xff0c;点击这个链接&#xff0c;会向服务器发送Http请求&#xff0c;加载这个链接指向的页面&#xff0c;在这个Http请求头里&#xff0c;会包含一个Referrer的标头&#xff0c;用于向服务器说明这个Http请求是从哪个页面跳转过来的&#xff0c;那么这…

SQL面试题1:连续登陆问题

引言 场景介绍&#xff1a; 许多互联网平台为了提高用户的参与度和忠诚度&#xff0c;会推出各种连续登录奖励机制。例如&#xff0c;游戏平台会给连续登录的玩家发放游戏道具、金币等奖励&#xff1b;学习类 APP 会为连续登录学习的用户提供积分&#xff0c;积分可兑换课程或…

LeetCode_5. 最长回文子串

最长回文子串https://leetcode.cn/problems/longest-palindromic-substring?envTypeproblem-list-v2&envId2cktkvj 给你一个字符串 s&#xff0c;找到 s 中最长的 回文子串 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" …

3D目标检测数据集——Waymo数据集

Waymo数据集簡介 发布首页&#xff1a;https://waymo.com/open/ 论文&#xff1a;https://openaccess.thecvf.com/content_CVPR_2020/papers/Sun_Scalability_in_Perception_for_Autonomous_Driving_Waymo_Open_Dataset_CVPR_2020_paper.pdf github&#xff1a;https://github.…

如何在 Linux、MacOS 以及 Windows 中打开控制面板

控制面板不仅仅是一系列图标和菜单的集合&#xff1b;它是通往优化个人计算体验的大门。通过它&#xff0c;用户可以轻松调整从外观到性能的各种参数&#xff0c;确保他们的电脑能够完美地适应自己的需求。无论是想要提升系统安全性、管理硬件设备&#xff0c;还是简单地改变桌…