精选力扣,牛客链表面试题

news2024/9/23 9:36:40

💎 欢迎各位大佬互三:我的主页

1. 反转链表

206.反转链表

思考:如果不开辟额外的空间,只在原来的链表上进行修改的话,该用什么方法呢

只需要从第二个元素开始,依次进行头插就可以了

接着修改一下引用就可以了,还要把末尾元素指向null

class Solution {
    public ListNode reverseList(ListNode head) {
        //head为null,直接返回
        if(head == null){
            return head;
        }

        ListNode cur = head.next;
        //head变为了末尾元素,指向null
        head.next = null;
        while(cur!=null){
            //curn为cur的next节点,便于往后移动
            ListNode curn = cur.next;    
            cur.next = head;
            head = cur;
            //更新cur
            cur = curn;
        }
        return head;
    }
}

2. 链表的中间节点

876. 链表的中间结点

这道题首先想到的方法肯定是定义一个cnt ,遍历一遍链表,接着求出中间的数,再遍历返回值,这种方法很简单,那如果要求只遍历一遍链表就找出中间节点呢

这里提供一个新的思路:利用快慢指针,都从head开始,fast指针每次移动两个节点,slow每次移动一个节点,这样是不是就达到了最终的目的

接着我们来实现一下:

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

这样是不是效率就更高了

3. 返回倒数第k个节点

面试题 02.02. 返回倒数第 k 个节点

这道题首先想到的应该还是遍历一遍得到总的长度,接着再找倒数第k个节点,不过有了上一题的基础,就可以想到另一种方法:同样的,利用快慢指针,让fast先走 k-1 个节点,然后slow和fast同时走,当fast的next为null时,就表示fast走到了最后一个节点,此时的slow就是倒数第k个节点

这道题中指明了输入的k是合法的,就不用再额外的判断了,那如果k是不合法的怎么判断,并且要求,不能直接求链表的长度,所以slow就需要边走边判断

class Solution {
    public int kthToLast(ListNode head, int k) {
        if (head == null) {
            return -1;
        }
        ListNode fast = head;
        ListNode slow = head;
        int cnt = 0;
        while (cnt != k - 1) {
            //判断k的合法性,虽然本题不用判断
            fast = fast.next;
            if(fast == null){
                return;
            }
            cnt++;
        }
        //slow和fast同时移动

        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow.val;
    }
}

4. 合并链表

21. 合并两个有序链表

思路:只需要再定义一个新的节点newH,然后一次比较headA和headB的val,为了最后能找到合并之后的链表的头结点,还要定义一个tmp = newH,之后谁小tmp.next就指向谁

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode head = new ListNode();
        ListNode tmp = head;
    
        while(list1!=null&&list2!=null){
            if(list1.val < list2.val){
                tmp.next = list1;
                list1 = list1.next;
                tmp = tmp.next;
            }else{
                tmp.next = list2;
                list2 = list2.next;
                tmp = tmp.next;
            }
        }
        //判断剩余的情况
        if(list1!=null){
            tmp.next = list1;
        }else if(list2!=null){
            tmp.next = list2;
        }
        return head.next;
    }
}

5. 链表分割

CM11 链表分割

这个是牛客上的一道面试题,题意就是对链表进行分割,x左边是比x小的,右边是比x大的,并且不能改变原来的顺序

思路:定义一个新的节点cur遍历原来的链表(防止原来的链表被改变),把比x大的都放到一个链表,比x小的都放在领一个链表,最后把这两个链表相连

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) {
                //处理刚开始为null的情况
                if (bs == null) {
                    bs = be = cur;
                }else{
                    be.next = cur;
                    be = be.next;
                }
            }else{
                if(as == null){
                    as = ae = cur;
                }else{
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //都是比x大的情况
        if(bs == null){
            return as;
        }
        be.next = as;
        //最后都要置为null,不然可能会报错
        if(as!=null){
            ae.next = null;
        }
        return bs;
    }
}

需要注意的是,如果都比x大,也就是bs = null,此时就直接返回as,还有就是如果最后要把as.next置为null

6. OR36 链表的回文结构

OR36 链表的回文结构

是牛客的一道题,因为其中有时间复杂度和空间复杂度的要求,意味着不能额外开数组,不然空间复杂度过不去,正常遍历就是O(n)的复杂度

思路是这样的:首先找到链表的中间节点slow,然后把从中间到末尾这部分进行反转,head节点往后遍历,slow也往后遍历,进行比较,如果值不相同,就意味着不是回文结构

反转链表和找中间节点前面已经练习过

public class PalindromeList {
    public boolean chkPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }
        //找到中间节点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        //从slow开始到末尾反转
        ListNode cur = slow.next;
        while (cur != null) {
            ListNode curn = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curn;
        }
        //判断回文
        while (head != slow) {
            if (head.val != slow.val) {
                return false;
            }
            //判断偶数节点
            if (head.next == slow) {
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }
}

需要注意的是,奇数节点的链表和偶数节点的链表的判断也有区别

偶数节点移动到上面的这种情况就会死循环,所以对于偶数节点还要额外判断

7. 相交链表

160. 相交链表

相交链表也就是一个类似于“ Y ”的转化,如图所示

下面的题中的图也很清楚

思路:因为无论是A短还是B短,他们的差值都是相交前的一部分,只需要把长的链表移动一个差值,接着两个链表节点同时往后移动,他们相同的节点就是要相交的那个节点

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode pl = headA;
        ListNode ps = headB;
        int cnta = 0,cntb = 0;
        //计算两个链表的长度
        while(pl!=null){
            pl = pl.next;
            cnta++;
        }
        while(ps!=null){
            ps = ps.next;
            cntb++;
        }
        //如果链表b长,就更新pl,ps
        int len = cnta - cntb;
        //上面求长度时pl,ps都为空了,所以这里再重新指向
        pl = headA;
        ps = headB;
        if(len < 0){
            pl = headB;
            ps = headA;
            len = cntb - cnta;
        }
        //移动差值
        while(len!=0){
            pl = pl.next;
            len--;
        }
        //找到相交节点
        while(pl!=ps){
            pl = pl.next;
            ps = ps.next;
        }
        //链表不相交的情况
        if(pl == null) return null;
        return pl;
    }
}

最后还需要加上不相交的情况,虽然在本题中不加也能过,不过为了严谨性还是要加上

8. 环形链表

8.1 判断是否有环

141. 环形链表

怎么去判断一个链表是否有环:还是使用快慢指针,就像两个人在操场跑步,一个人跑的快,一个人跑的慢,由于操场是一个环形,所以跑的快的肯定可以超过跑的慢的一圈,这时他们就相遇,但如果不是环,他们永远也不能相遇,就像你怎么追都追不到的女神一样

但是还有一种情况,如果是两个节点的环,定义的fast指针一次走3步,slow指针一次走1步,那他们还是永远也相遇不了

所以定义的指针每次走几步也需要判断,如果一个走2步,一个走1步,肯定是能相遇的

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

8.2 返回入环口的节点

142. 环形链表 II

这次需要在上题中判断是否为环后找出进入环的入口点,可以进行以下推理

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //判断环
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) break;
        }
        if(fast == null||fast.next == null) return null;
        slow = head;
        //寻找环
        while(slow!=fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

需要补充的是:

当环很小的时候,最终的化简结果就变成了上面的,但原来的代码还是没问题的

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

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

相关文章

ROS2 + 科大讯飞 初步实现机器人语音控制

环境配置&#xff1a; 电脑端&#xff1a; ubuntu22.04实体机作为上位机 ROS版本&#xff1a;ros2-humble 实体机器人&#xff1a; STM32 思岚A1激光雷达 科大讯飞语音SDK 讯飞开放平台-以语音交互为核心的人工智能开放平台 实现步骤&#xff1a; 1. 下载和处理科大讯飞语音模…

Linux /etc/profile 详解

概述 Linux是一个多用户的操作系统。每个用户登录系统后&#xff0c;都会有一个专用的运行环境。通常每个用户默认的环境都是相同的&#xff0c;这个默认环境实际上就是一组环境变量的定义。用户可以对自己的运行环境进行定制&#xff0c;其方法就是修改相应的系统环境变量&…

python如何查看类的函数

Python非常方便&#xff0c;它不需要用户查询文档&#xff0c;只需掌握如下两个帮助函数&#xff0c;即可查看Python中的所有函数&#xff08;方法&#xff09;以及它们的用法和功能&#xff1a; dir()&#xff1a;列出指定类或模块包含的全部内容&#xff08;包括函数、方法、…

浅谈串口UART通信原理

文章目录 引言并行和串行波特率UART帧格式 引言 UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff0c;通用异步收发器&#xff09;是一种用于串行通信的硬件设备。它允许两个设备之间进行异步数据传输。是一种通用的串行、异步通信总线。该总线有两条数据…

SpringBoot整合XXL_JOB示例

XXL-JOB 是一个分布式任务调度平台&#xff0c;主要用于管理和执行定时任务。它适用于各种场景&#xff0c;例如定时任务、批处理任务、分布式任务等。XXL-JOB 提供了丰富的功能&#xff0c;使得任务调度变得简单、高效和可靠。以下是 XXL-JOB 的一些主要功能和特点&#xff1a…

Centos系统内磁盘分区

Centos系统内磁盘分区 建议如果有重要数据提前做好备份 以根目录扩容50G为例&#xff1a; 1、卸载/home目录 umount /home 2、删除逻辑卷 y确认即可 lvremove /dev/mapper/centos-home 3、df -h查询一下&#xff0c;/home目录已经不见了 4、向根目录分区追加50G容量 lv…

数据销毁境外间谍情报机关逼迫、威胁贷款学生为其窃取我国家秘密

近年来&#xff0c;随着国际形势的复杂多变&#xff0c;境外间谍情报机关的活动也日益猖獗。他们利用各种手段&#xff0c;包括通过校园贷逼迫、威胁贷款学生为其窃取我国国家秘密&#xff0c;这种行为不仅危害了国家安全&#xff0c;也严重损害了社会的公平正义。那么&#xf…

微信小程序毕业设计-汽车维修项目管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

(一)高并发压力测试调优篇——MYSQL数据库的调优

前言 在实际项目开发中&#xff0c;很多业务场景下都需要考虑接口的性能要求&#xff0c;追求高并发、高吞吐量。那么对于此类问题如何入手呢&#xff1f;关注作者&#xff0c;不迷路。本节内容主要介绍在数据库db方面的优化&#xff0c;以mysql数据库为例。 关于db的优化&am…

python库(11):Box库简化字典和对象之间的转换

1Box库简介 Box是一个Python库&#xff0c;它提供了一种将数据封装在字典和列表中的方式&#xff0c;同时提供了一些额外的功能&#xff0c;比如数据验证、默认值设置等。这使得Box库非常适合用于配置管理、数据传输对象&#xff08;DTO&#xff09;的创建&#xff0c;以及任何…

PDF 中图表的解析探究

PDF 中图表的解析探究 0. 引言1. 开源方案探究 0. 引言 一直以来&#xff0c;对文档中的图片和表格处理都非常有挑战性。这篇文章记录一下最近工作上在这块的探究。图表分为图片和表格&#xff0c;这篇文章主要记录了对表格的探究。还有&#xff0c;我个人主要做日本项目&…

[C++]——同步异步日志系统(4)

同步异步日志系统 一、日志等级模块设计二、日志消息类设计 一、日志等级模块设计 定义出日志系统所包含的所有日志等级分别为&#xff1a;&#xff08;7个等级&#xff09; UNKNOW0&#xff0c;未知等级的日志DRBUG &#xff0c;调试等级的日志INFO &#xff0c;提示等级的日…

前端调试技巧(npm Link,vscode调试,浏览器调试等)

Npm Link 功能&#xff1a; 在本地开发npm模块的时候&#xff0c;我们可以使用npm link命令&#xff0c;将npm 模块链接到对应的运行项目中去&#xff0c;方便地对模块进行调试和测试 断点调试 vscode调试 Debug Vue2 Project 目标&#xff1a;在VSCode中调试项目代码…

docker拉取镜像-配置阿里云镜像加速

1、配置阿里云镜像&#xff08;用于拉取镜像加速&#xff09; sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo syst…

论文阅读【时间序列】TimeMixer (ICLR2024)

【时间序列】TimeMixer (ICLR2024) 原文链接&#xff1a;TIMEMIXER: DECOMPOSABLE MULTISCALE MIXING FOR TIME SERIES FORECASTING 代码仓库&#xff1a;https://github.com/kwuking/TimeMixer 符号定义 符号含义P用于预测的历史序列长度&#xff08;seq_len&#xff09;F预测…

debian 12 Install

debian 前言 Debian是一个基于Linux内核的自由和开放源代码操作系统&#xff0c;由全球志愿者组成的Debian项目维护和开发。该项目始于1993年&#xff0c;由Ian Murdock发起&#xff0c;旨在创建一个完整的、基于Linux的自由软件操作系统。 debian download debian 百度网盘…

LangChain之工具Tools(下)

LangChain之工具Tools SQLDatabase工具准备数据初始化数据库光标查询​字符串查询带参数查询​使用SQLAlchemy查询​使用自然语言查询数据库 使用其他工具Tavily Search工具Dall-E图像生成工具ArXiv工具 SQLDatabase工具 在 LangChain 中,SQLDatabase工具可以用来与SQL数据库进…

和Bug较劲的第n天:[Error: Unable to open snapshot file: No such file or directory]

问题描述 最近做了一个小demo&#xff0c;基于parcel的&#xff0c;在迁移仓库的时候发生了一个报错 [Error: Unable to open snapshot file: No such file or directory] 原因分析&#xff1a; 在迁移仓库的时候&#xff0c;我将项目放入了一个以中文命名的文件夹里&#xf…

在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——安装篇(一)

#在生产环境中部署Elasticsearch&#xff1a;最佳实践和故障排除技巧——安装篇&#xff08;一&#xff09; 前言 关键字&#xff1a; 机器学习 人工智能 AI chatGPT 学习 实现 使用 搭建 深度 python 事件 远程 docker mysql安全 技术 部署 技术 自动化 代码 文章目录 - -…

【斯坦福因果推断课程全集】2_无混淆和倾向分1

目录 Beyond a single randomized controlled trial Aggregating difference-in-means estimators Continuous X and the propensity score 随机试验的一个最简单的扩展是无约束下的干预效果估计。从定性上讲&#xff0c;当我们想估计一种并非随机的治疗效果&#xff0c;但一…