LinkedList和链表之刷题课(上)

news2024/11/26 16:48:01

在上一节,我们自己实现了一个单链表的结构,接下来我们来写几个面试题巩固一下

1. 删除链表中等于给定val的所有结点

        解析题目:

如图,我们需要删除所有的值为12的结点

       在head非空的情况下,我们删除一个结点,首先要找到这个结点,然后把这个结点的前面一个结点的next指向这个节点的下一个,这个就是总体的步骤,不过我们不止删除一个结点,我们需要删除所有是val值的结点,因此综上,我们需要俩个指针,prev和cur,prev指向的是删除结点的前一个结点,cur就是删除结点的当前节点,因此我们一开始先设置prev = head,cur = head.next;然后我们进入循环,如果当前的cur.val==key,我们就需要让prev.next = cur.next,然后我们需要跟新cur,cur = cur.next,如果我们当前节点的值不等于key,那么我们需要让prev = cur;cur=cur.next;

        上面就大致解决了这个问题,但是我们还漏了一点,那就是head节点,head节点我们并没有判断它是否和val值一致.并且这行代码必须在删除完中间节点之后再删除,不然要用while,因为我们考虑到这种情况:1,1,1,2,2,1;我们如果一开始就删去1,那么第二个1是不可能被删除的,因为我们后期也没处理新的头结点的key,这一点同样也要在上一节博客修改一下.

整体代码:

 public void removeAllKey(int key) {
        //判断头节点是不是空的
        if (this.head == null) {
            return;
        }
        //判断头结点是不key
        if (head.val == key) {
            this.head = this.head.next;
        }
        ListNode prev = head;
        ListNode cur = head.next;
        //我们遍历除了head后面的元素
        while (cur != null) {
            if (cur.val == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
    }

2. 翻转一个单链表

        解析题目:

        我们翻转一个链表,也就是要把从最后一个节点开始,把它的next指向它的前一个

        

    此时,我们可以采用头插法来,我们用cur记录当前节点,cur = head.next;然后我们需要把head.next置空,因为此刻head指向的节点是相当于我们翻转之后的最后一个节点.然后我们在把cur插到head前面的时候,我们需要用curNext来记录后面的节点,不然后续我们头插完,就找不然原先的链表了.然后我们需要跟新head,head = cur完成一轮插入,然后我们需要跟新cur,让cur指向curNext,再让curNext记录下一个节点.

还有个小地方,也就是我们如果链表head == null 或者head.next == null我们直接返回head即可,因为没有必要翻转.

整体代码:

 //TODO 翻转链表
    public ListNode reverseList() {

            //判断链表是不是空的
        if(head == null) {
            return null;
        }
        //如果只有一个结点,就直接返回head即可
        if(head.next == null){
            return head;
        }

        //其他情况就用头插法
        ListNode cur = head.next;
        head.next = null;
        while (cur != null) {
            //把head置空
            //记录下一个节点的位置
            ListNode curNext = cur.next;
            //把cur头插进去
            cur.next = head;
            //跟新head
            head = cur;
            //跟新cur
            cur = curNext;
        }
        //返回head
        return head;

    }

3. 给定一个带有头节点的非空单链表,返回链表的中间结点.如果有俩个中间结点,则返回第二个中间结点.

        解析题目:

        我们可以看见,我们返回中间结点,要分偶数个结点和奇数个结点.

        我们先来看法1: 1> 求出整个链表的大小;2>找到len/2的结点

因为过于简单,我们这里就不画图了,直接解释代码:

先判断整个链表head是不是null;然后进入主题,求len,我们的循环条件是cur!=null,因为我们需要遍历所有的结点,如果用cur.next!=null;我们就会漏掉最后一个结点.然后注意,我们需要让cur重新指向head,因为cur刚刚在遍历的时候已经为null了;我们再设置一个计数变量i,中间长度mid,我们每次cur-cur.next;我们就需要对i进行++;

  public ListNode  middleNode() {
        if(head==null){
            return null;
        }
    //先求整个链表的长度
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        cur = head;
        //再求长度/2找到这个中间节点
        int mid = len / 2;
        int i = 0;
        while (i != mid) {
            cur = cur.next;
            i++;
        }

        return cur;
    }

        法2 快慢指针,一开始fast和slow都指向head,然后fast走俩步,slow走一步;

        这里因为奇偶数结点会分俩个情况,fast结束的标志会有俩种情况,也就是:fast == null和fast.next == null;在fast满足上面的情况之一就会说明slow到达了中间结点了.

这里我们解决俩个问题即可:

1> 为什么先判断fast再判断fast.next;

2> 为什么不能用||要用&&

        整体代码:

public ListNode  middleNodeFastAndSlow() {
        if(head == null){
            return null;
        }
         //我们定义俩个指针
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            //fast一次走俩步,slow一次走一步
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
        //俩个点
        //1.为什么不能用||要用&& 因为如果是偶数个,最后我们fast会为null,因此判断fast.null会显示空指针异常
        //2.为什么先要判断fast,再判断fast.next:因为如果是偶数个,fast最后会走到null,这时候先判断fast.next!=null会空指针异常

    }

4. 输入一个链表,输出该链表中倒数第k个结点

        题目解析:

这个题目其实也有俩个方法,但是我们这里主要用快慢指针来解题

假设我们求的是倒数第k个结点,我们先让fast先走k-1步,然后我们再让fast和slow一起走,直到fast ==null为止;这个东西我是这么理解的,我们相当于把fast作为一个我们自定义的动态边界条件,让它先走k-1步,再同时走,这样fast肯定会先到最后一个结点,然后此时我们的slow所在位置就是倒数第k个结点.slow和fast相差k-1步.

        然后我们这里要判断我们所要的结点的下标的合法性,此时我们我们可以优化一下k>size()这个条件,因为如果k很大,我们要遍历O(n),因为我们的fast要走k-1步,此时我们也需要一个循环,所以,我们直接去在这里面判断fast == null

        整体代码:

//TODO 输出链表倒数第k个结点
    //slow和fast总是差k-1
    public ListNode FindtheToTail(int k) {
        //先判断k的合法性
        if(k < 0) {//我们可以优化一下这个k>siez()
            return null;
        }
        //并且判断head是不是空
        if (head == null) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        //fast走k-1步
        for (int i = 0; i < k-1; i++) {
            fast = fast.next;
            //TODO 优化size()不去遍历,这个就是去处理k太大的情况
            if(fast == null) {
                return null;
            }
        }
        //同时走
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        //fast到最后,slow的位置就是倒数第k个
        return slow;
    }

5. 将俩个有序链表合并成一个新的有序链表并返回.

        题目解析:

差不多是这么个情况,我们有俩个有序的链表,我们要把俩个合并成一个新的有序链表.我们先构造一个虚拟结点newH,然后我们再让list1和list2(此处,图上的head1就是list1,head2就是list2)互比较,小的就把该结点尾插到newH上去

具体步骤如图,我们要记录虚拟结点的位置,因此创建一个tmpH指向一开始的newH,我们把list1和list2的val进行比较,小的那一方,把该结点和newH连接在一起,如果是list1小,那么tmpH.next = list1;然后我们跟新list1,list=list.next;然后我们也要跟新newH,因为它指向的是链表的尾巴,我们进行尾插法,直到有一个链表为空为止

我们如图可以知道list2已经遍历完了,我们直接把list1剩下的元素连接过来即可,最后我们返回headH.next即可(因为headH是个虚拟结点)

        整体代码:

//TODO 合并俩个有序列表
    public static MySingleList.ListNode mergeTwoLists(MySingleList.ListNode list1, MySingleList.ListNode list2) {
         //先生成一个开头的结点
       MySingleList.ListNode newH = new MySingleList.ListNode(-1);
         //tmpH始终指向的是链表的尾巴
       MySingleList.ListNode tmpH = newH;

       //判断俩个链表是不
         while (list1 != null && list2 != null) {
            //先比较list1和list2指向的结点,我们把小的值链接上
             if(list1.val < list2.val) {
                 //小的话就把小的链接到newH上
                 tmpH.next = list1;
                 //跟新list1
                 list1 = list1.next;
             } else {
                 //小的话就把小的链接到newH上
                 tmpH.next = list2;
                 //跟新list2
                 list2 = list2.next;
             }
             System.out.println("while末尾");
             //tmpH始终指向的是链表的尾巴
             tmpH = tmpH.next;
         }
         //如果其中一个为空了,那么就把另外一个链接过来即可
         if(list1 != null) {
             tmpH.next = list1;
         }
         if (list2 !=null){
             tmpH.next = list2;
         }
         return newH.next;

    }

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

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

相关文章

neutron组件

1.实现虚拟交换机有两种方式 2.HCS网络节点 华为 HCS 将网络节点单独部署&#xff0c;且部署两台(主备部署) 两张万兆网卡&#xff0c;否则检测无法通过 L3 agent 部署在哪个节点&#xff0c;哪个节点就是网络节点 DHCP agent metadata agent 3.neutron概念 3.1Neutron支持…

10. DAX 时间函数之实战

在实际代码过程中&#xff0c;总会遇到各种需求&#xff0c;往往需要一个或者多个函数一起实现目的。在下面的过程中&#xff0c;我尽量使用简洁而优美的代码&#xff0c;来实现各个目的。 首先准备数据&#xff0c;使用 1. DAX 时间函数--生成日期表 中的 GENERATE CALENDAR …

服务器卸载 mysql

服务器卸载 mysql 1.卸载安装的mysql #查看安装的mysql rpm -qa|grep -i mysql在这里插入图片描述 #卸载 rpm -ev 名称 --nodeps rpm -ev mysql-libs-8.0.26-1.module_el8.4.0915de215114.x86_64 --nodeps2.删除相关文件 find / -name mysql rm -rf /var/lib/mysql3.删除配…

西南交通大学计算机软件专业上岸难度分析

C哥专业提供——计软考研院校选择分析专业课备考指南规划 西南交通大学计算机科学与技术2024届考研难度整体呈现"稳中有升"的态势。学硕实际录取33人&#xff0c;复试分数线362分&#xff0c;复试录取率71.74%&#xff1b;专硕&#xff08;计算机技术&#xff09;实际…

Java 输入与输出(I/O)流的装饰流【处理流】

Java I/O流的装饰流 按照Java 输入与输出&#xff08;I/O)流的处理功能&#xff1a;I/O流可分为低级的节点流和高级的装饰流&#xff08;又称处理流&#xff09;。 节点流是直接从数据源&#xff08;数据源可以是文件、数组、内存或网络&#xff09;读/写数据的输入输出流&am…

021_Thermal_Transient_in_Matlab统一偏微分框架之热传导问题

Matlab求解有限元专题系列 固体热传导方程 固体热传导的方程为&#xff1a; ρ C p ( ∂ T ∂ t u t r a n s ⋅ ∇ T ) ∇ ⋅ ( q q r ) − α T d S d t Q \rho C_p \left( \frac{\partial T}{\partial t} \mathbf{u}_{\mathtt{trans}} \cdot \nabla T \right) \nab…

三个必须了解的知乎知+广告账户知识!

作为国内领先的问答社区&#xff0c;知乎以其高质量的内容和深度讨论吸引了大量专业和兴趣导向的用户群体。对于希望精准触达目标用户的广告主来说&#xff0c;知乎的信息流广告无疑是一个不可多得的营销渠道&#xff0c;云衔科技助力企业知乎广告开户投放及代运营服务。 1. 知…

【rom分享】PSP体育游戏大众高尔夫玩法介绍,不要错过

各位新老观众大家好&#xff0c;今天我将介绍知名掌机PSP的所有游戏&#xff0c;PSP的游戏库非常庞大&#xff0c;随着PSP模拟器的普及&#xff0c;你可以在安卓和苹果两大平台的移动设备上游玩&#xff0c;也可以在PC上面游玩&#xff0c;当然你也可以收藏一个PSP掌机进行游玩…

python3的语法及入门(近7000字,耐心看包全,看完记得点赞)!

1. Python3 基础语法 缩进&#xff1a;Python 使用缩进来表示代码块&#xff0c;通常使用 4 个空格。 语句&#xff1a;一行代码就是一个语句。 变量&#xff1a;不需要声明类型&#xff0c;直接赋值即可。 2. Python3 基本数据类型 Python 中的基本数据类型包括整数、浮点…

Shell学习——shell中的变量

目录 一、父shell和子shell&#xff1a; 二、系统预定变量 定义方式&#xff1a; 脚本举例 ​编辑 四、只读变量 五、撤销变量 六、小结 七、特殊变量 $n $# $*、$ $? 一、父shell和子shell&#xff1a; 由于shell的原理可以理解为套娃&#xff0c;因此有父shell…

【实战案例】Django框架连接并操作数据库MySQL相关API

本文相关操作基于上次操作基本请求及响应基础之上【实战案例】Django框架基础之上编写第一个Django应用之基本请求和响应 Django框架中默认会连接SQLite数据库&#xff0c;好处是方便无需远程连接&#xff0c;打包项目挪到其他环境安装一下依赖一会就跑起来&#xff0c;但是缺点…

你知道吗?这个岗位只招2人,但HR那边却收到了1w份简历

引言 在当前经济环境下&#xff0c;求职者面临的挑战越来越大。互联网行业尤其如此&#xff0c;许多人挤破头都想进入大厂&#xff0c;但竞争异常激烈。如今的就业市场确实变得异常艰难。然而&#xff0c;随着AI大模型技术的兴起&#xff0c;对于那些掌握了相关技能的专业人才…

学习笔记——交换——STP(生成树)基本概念

三、基本概念 1、桥ID/网桥ID (Bridege ID&#xff0c;BID) 每一台运行STP的交换机都拥有一个唯一的桥ID(BID)&#xff0c;BID(Bridge ID/桥ID)。在STP里我们使用不同的桥ID标识不同的交换机。 (2)BID(桥ID)组成 BID(桥ID)组成(8个字节)&#xff1a;由16位(2字节)的桥优先级…

Java基于SSM微信小程序物流仓库管理系统设计与实现(lw+数据库+讲解等)

选题背景 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…

wordcloud分词生成

代码如下 _ from wordcloud import WordCloud import PIL.Image as image import numpy as np import jiebadef cut(text):word_list jieba.cut(text,cut_all True)# 分词后在单独个体之间加上空格result " ".join(word_list)return result#导入文本文件,进行分词…

免费ppt模板从哪找?全面又实用的PPT模板就在这找

就是说有多少刚上大学的朋友&#xff0c;为了交一份完美的PPT报告&#xff0c;手写列大纲、找报告文献/插图素材......最后手动整理排版&#xff0c;老老实实地熬了几个大夜&#xff1f; 24年都快结束啦&#xff0c;大家还没学会去免费的ppt模板网站下载精美的主题PPT一键替换吗…

政安晨【零基础玩转各类开源AI项目】基于本地Ubuntu (Linux ) 系统应用Gradio-Lite:无服务器 Gradio 完全在浏览器中运行

目录 简介 什么是@gradio/lite? 入门 1.导入 JS 和 CSS 2. 创建标签 3. 在标签内编写你的 Gradio 应用程序 更多示例:添加其他文件和要求 多个文件 其他要求 SharedWorker 模式 代码和演示playground 1.无服务器部署 2.低延迟 3. 隐私和安全 限制 尝试一下!…

VScode远程开发之remote 远程开发(二)

VScode远程开发之remote 远程开发&#xff08;二&#xff09; 使用vscode进行远程开发很简单&#xff0c;在拓展里搜索 Remote Development&#xff0c;就可以搜索到微软提供的远程开发大礼包&#xff0c;里面包含了 通过 SSH 远程服务器 远程容器 远程 WSL&#xff08;Win…

亚马逊测评自养号技术及采购下单成功率揭秘

在亚马逊测评中&#xff0c;自养号面临砍单、买家号关联等问题时&#xff0c;需要采取一系列策略和技术手段来提高采购下单的成功率。以下是一些具体的解决方案&#xff1a; 一、解决砍单问题 1.确保硬件参数独立 每个账号应使用具有独特硬件标识的设备&#xff0c;如IMEI、…

【大模型实战篇】大模型分词算法WordPiece分词及代码示例

继《大模型数据词元化处理BPE(Byte-Pair Encoding tokenization)》之后&#xff0c;我们针对大模型原始数据的分词处理&#xff0c;继续分享WordPiece分词技术【1】。 1. 原理分析 WordPiece 是 Google 开发的分词算法&#xff0c;用于预训练 BERT。此后&#xff0c;它被多个基…