Java LeetCode篇-深入了解关于单链表的经典解法

  🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
 

文章目录

        1.0 移除链表元素

        1.1 使用双指针方法

        2.0 反转链表

        2.1 递归法

        2.2 头插法

        3.0 链表中倒数第 k 个节点

        3.1 递归法

        3.2 快慢指针

        4.0 合并两个有序链表

        4.1 递归法

        4.2 尾插法

        5.0 链表的回文结构

        5.1 双指针与反转

        6.0 环形链表

        6.1 快慢指针

        7.0 相交链表

        7.1 暴力解法

        7.2 计算长度


        1.0 移除链表元素

题目:

        给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

该题的链接为:203. 移除链表元素 - 力扣(LeetCode)

        1.1 使用双指针方法

         具体思路为:先来考虑如何删除目标节点,定义两个指针,对于 fast 这个指针来说:一开始就指向 head.next 的节点,然后一步步往后走,在每一次走之前需要判断 fast.val 是否与目标值 val 相等对于 slow 这个指针来说,一开始指向 head 节点,跟着 fast 指向节点的后面的节点,如果 fast.val == val 这个两个值相等就意味着需要删除该节点,则 slow.next = fast.next ,就删除了该节点了;如果  fast.val == val 这个两个值不相等,fast = fast.next 与 slow = slow.next 继续往后走,循环结束的条件为:fast == null 。最后直接返回头节点。

代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode removeElements(ListNode head, int val) {if(head == null) {return null;}ListNode slow = head;ListNode fast = head.next;while(fast != null) {if(fast.val == val) {slow.next = fast.next;fast = slow.next;}else {fast = fast.next;slow = slow.next;}}   if(head.val == val) {head = head.next;} return head;}
}

        需要注意的是,当遇到要删除的节点就为 head 的情况,还需要多加一个条件,如果 head.val == val 时,需要将头节点往后移,head = head.next 。这段代码需要放到循环结束之后,万万不可将这段代码加在对 head 判空后面,也就是循环之前。

解释为什么只能放在循环后面的原因:

        举个例子就好了,举例 7 -> 7 -> 7 -> 7 -> null 这一段代码,需要是要删除节点的 val 为 7,那么如果将  if(head.val == val) { head = head.next;   }  这段代码放在循环之前,得出来的最终结果是 7 -> null ,我们可以发现是没有将节点值为 7 删除完全;如果将以上的代码放在循环之后,那么最终的结果为 null,符合要求的节点被完全删除了。

        

        2.0 反转链表

题目:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

该题的链接为:206. 反转链表 - 力扣(LeetCode)

        2.1 递归法

        具体思路为:先考虑反转后的头节点,也就是当前的尾节点,那么这个可以通过递出到底时拿到尾节点直接返回,再通过回归过程中一层层返回出来;再来考虑将中间的各个节点的指向反转,这也不难实现,也就是在回归过程中,将当前的节点的下一个节点指向当前节点即可,需要注意的是,还需要将当前节点的指向置为 null 。

代码如下:

class Solution {public ListNode reverseList(ListNode head) {return reverse(head);}public ListNode reverse(ListNode p) {if(p == null || p.next == null) {return p;}ListNode ret = reverse(p.next);p.next.next = p;p.next = null;return ret;}
}

        递归结束条件有两种情况:第一种,若该链表为 null ,则没有必要继续下去了第二种情况,当递归到 p.next == null 时,返回该节点,也就是反转后的头节点

        2.2 头插法

        具体思路为:需要先定义两个指针,对于 n2 指针来说,一开始就指向 head.next 节点对于 n1 指针来说,一开始就指向 head 节点。循环过程: head.next = n2.next ,需要将 n2 后面的节点被 head 头节点引用,然后再将 n2.next = n1,这个过程就是头插过程,将后面的节点插到节点的最前面,再然后重新赋值头节点 n1 = n2 ,此时,n1 就是该链表中的头节点了,最后再让 n2 = head.next 继续下去。循环结束条件为:n2 == null 时,结束循环。返回头节点 n1

代码如下:

class Solution {public ListNode reverseList(ListNode head) {if(head == null) {return null;}ListNode n1 = head;ListNode n2 = head.next;while(n2 != null) {head.next = n2.next;n2.next = n1;n1 = n2;n2 = head.next;}return n1;}
}

        需要注意的是:需要将 head 进行判空处理。

        3.0 链表中倒数第 k 个节点

题目:

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

示例1

输入:

1,{1,2,3,4,5}

复制返回值:

{5}

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

        3.1 递归法

        具体思路为:需要先定义两个成员变量,对于 int sum 来说,其作用就是用来计数对于 ListNode end 来说,记录找到的节点。该递归不需要返回值,只要 p.next != null 时,就一直递出下去,一旦 p.next == null 时,回归过程中需要先 sum++ ,再来判断 sum 是否等于 k ,若两个值相等时,需要将 end 指向当前节点;无论该两个值相不相等,需要一直回归下去。

代码如下:

import java.util.*;
/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class Solution {private ListNode end;private int sum ;public ListNode FindKthToTail(ListNode head,int k) {end = null;sum = 0;if(head == null) {return null;}recursion(head,k);return end;}public void recursion(ListNode p, int k) {if(p.next != null) {recursion(p.next, k);}sum++;if(sum == k) {end = p;}}}

         注意的是:需要进行对 head 判空处理。

        3.2 快慢指针

        具体思路:对于 fast 指针来说,一开始的时候,指向 head 对于 slow 指针来说,一开始的时候,指向 head先让 fast 先走 k 步,再跟 slow 一起走,直到 fast == null 时,当前的 slow 则为目标的节点,倒数第 k 个节点

代码如下:

import java.util.*;
/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class Solution {public ListNode FindKthToTail(ListNode head,int k) {if(head == null) {return null;}ListNode fast = head;ListNode slow = head;int count = 0;while(count < k) {if(fast == null) {return null;}fast = fast.next;count++;}while(fast != null) {fast = fast.next;slow = slow.next;}return slow;}
}

        需要注意的是:1.需要先对 head 进行判空处理2. 在 fast 走 k 步的过程中,有可能会越界,所以要加上判断

        4.0 合并两个有序链表

题目:

        将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

该题的链接为:21. 合并两个有序链表 - 力扣(LeetCode)

        4.1 递归法

        具体思路为:先来考虑递出的过程中,判断 l1.val l2.val 的大小,若 l1.val < l2.val 时,需要将 l1 移到下一个节点;若 l2.val <= l1.val 时,需要将 l2 移到下一个节点。再来考虑回归过程,当任意一个链表为 null 时,就返回另一条不为 null 的链表,需要用当前的节点来接收。

代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {if(list1 == null) {return list2;}if(list2 == null) {return list1;}if(list1.val > list2.val) {list2.next = mergeTwoLists( list1,list2.next);return list2; }else {list1.next = mergeTwoLists( list1.next, list2);return list1;}}}

        4.2 尾插法

        具体思路为:先定义出 ListNode newHead = new ListNode();称为哨兵节点,也就是傀儡节点,再定义一个 ListNode  p  = newHead 临时变量一开始的时候指向哨兵节点。接着,让两个链表中的一个个节点分别进行对比,若 l1.val < l2.val 时,p.next = l1 ,就需要将 p.next 指向 val 较小的节点,然后 l1 = l1.next ,l1 往后移一步,再跟 l2 中的节点进行比较,最后还要让 p = p.next 往后移一步,以此类推下去。直到任意一条的链表为 null 时,p.next 指向不为 null 的链表。

代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode newHand = new ListNode();ListNode p = newHand;while(list1 != null && list2 != null) {if(list1.val < list2.val) {p.next = list1;list1 = list1.next;p = p.next;}else {p.next = list2;list2 = list2.next;p = p.next;}}if(list1 != null) {p.next = list1;}if(list2 != null) {p.next = list2;}return newHand.next;}
}

        需要注意的是,返回傀儡节点的下一个节点,即头节点。

        5.0 链表的回文结构

题目:        

        对于一个链表,请设计一个时间复杂度为 O(n) ,额外空间复杂度为 O(1) 的算法,判断其是否为回文结构。

给定一个链表的头指针 A,请返回一个 bool 值,代表其是否为回文结构。保证链表长度小于等于 900。

测试样例:

1->2->2->1
返回:true

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

        5.1 双指针与反转

        具体思路为:通过双指针这个算法来找到中间节点,再将中间节点开始的链表进行反转,最后进行遍历比较每一个节点是否相等

        对判断回文链表更加详细的介绍点击一下链接:Java 算法篇-链表的经典算法:判断回文链表、判断环链表与寻找环入口节点(“龟兔赛跑“算法实现)-CSDN博客

代码如下:

import java.util.*;/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class PalindromeList {public boolean chkPalindrome(ListNode A) {// write code hereListNode slow = A;ListNode fast = A;ListNode p = A;//找中间节点while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}//然后进行反转ListNode pp = recursion(slow);while(pp != null) {if(pp.val != p.val) {return false;}pp = pp.next;p = p.next;}return true;}public ListNode recursion(ListNode p) {if(p.next == null || p == null) {return p;}ListNode last = recursion(p.next);p.next.next = p;p.next = null;return last;}
}

        6.0 环形链表

题目:

        给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

该题的链接为:141. 环形链表 - 力扣(LeetCode)

        6.1 快慢指针

        具体思路为:定义两个指针,每一个指针的每一次走的步数都不一样,然后一直循环下去,判断 p == null 就停止循环,否则一直下去,那么一直下去就说明有环,所以无论如何,该两个指针总会有相遇的时候

        对判断回文链表更加详细的介绍点击一下链接:Java 算法篇-链表的经典算法:判断回文链表、判断环链表与寻找环入口节点(“龟兔赛跑“算法实现)-CSDN博客

代码如下:

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public boolean hasCycle(ListNode head) {if(head == null) {return false;}ListNode fast = head.next;ListNode slow = head;while(fast != null && fast.next != null) {if(slow == fast) {return true;}slow = slow.next;fast = fast.next.next;}return false;}
}

        7.0 相交链表

题目:

        给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

该题的链接为:160. 相交链表 - 力扣(LeetCode)

        7.1 暴力解法

        具体思路为:直接去通过遍历来寻找 A 链表中的节点是否在 B 链表中,若找到了,则返回该节点;若没找到,说明该两条链表不相交,返回 null 。

代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode p = headA;while( p != null ) {ListNode q = headB;while(q != null) {  if(q == p) {return p;}q = q.next;}p = p.next;}return null;}
}

       7.2 计算长度

        具体思路为:我们可以想到,能不能把两个链表变成等长的链表呢?显然若两链表不等长,那么长的链表的前 n 个结点(n 是长链表比短链表多的结点数)显然不可能是公共结点。而剩余部分两链表是等长的,自然就可以按照顺序同步后移的方法查找公共结点。

不过,为确定两链表长度差,得先遍历两链表确定长度。

代码如下:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode p = headA;ListNode q = headB;int s1 = 0;int s2 = 0;while(p != null) {s1++;p = p.next;}while(q != null) {s2++;q = q.next;}p = headA;q = headB;while(s1 < s2) {q = q.next;s2--;}while(s2 < s1) {p = p.next;s1--;}while(p != null && q != null) {if(p == q) {return q;}q = q.next;p = p.next;}return null;}    
}

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

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

相关文章

【每日一题】1670. 设计前中后队列-2023.11.28

题目&#xff1a; 1670. 设计前中后队列 请你设计一个队列&#xff0c;支持在前&#xff0c;中&#xff0c;后三个位置的 push 和 pop 操作。 请你完成 FrontMiddleBack 类&#xff1a; FrontMiddleBack() 初始化队列。void pushFront(int val) 将 val 添加到队列的 最前面…

如何通过“闻香”给葡萄酒分类?

有句话叫做“闻香识女人”&#xff0c;葡萄酒也如同美女&#xff0c;千娇百媚风情万种&#xff0c;所以通过“闻香”也可以给葡萄酒进行分类。 那么&#xff0c;云仓酒庄的品牌雷盛红酒分享葡萄酒都有哪些不同的香呢&#xff1f; 云仓酒庄是云仓酒庄的结合&#xff0c;也就是在…

计算机网络(超详解!) 第二节 物理层(上)

1.物理层的基本概念 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层的作用是要尽可能地屏蔽掉不同传输媒体和通信手段的差异。 用于物理层的协议也常称为物理层规程(procedure)。 2.物理层的主要任务 主要…

vivado产生报告阅读分析21

其他命令选项 • -of_objects <suggestion objects> &#xff1a; 启用特定建议的报告。在此模式下运行时 &#xff0c; report_qor_suggestions 不会生成新建议。此命令可快速执行 &#xff0c; 读取 RQS 文件后 &#xff0c; 此命令可用于查看其中包 含的建议。其…

流程控制翻转学习

&#x1f4d1;前言 本文主要是【Python】——Python流程控制翻转学习的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每…

OSHI-操作系统和硬件信息库

文章目录 引言一、快速入门1.1 OSHI的简介1.2 引入依赖1.3 涉及的包&#xff08;package&#xff09;1.4 涉及的核心类 二、操作系统信息&#xff1a;OperatingSystem2.1 总揽2.2 文件系统信息&#xff1a;FileSystem2.3 网络参数信息&#xff1a;NetworkParams2.4 进程信息&am…

Docker,从入门到精通

1、DockerFile 介绍 dockerfile 是啥?dockerfile 用来构建 docker 镜像的文件。 具体步骤&#xff1a; 1、编写一个 dockerfile 文件 2、docker build 构造一个镜像 3、docker run 运行镜像 4、docker push 发布镜像 DockerFile 构建过程 1、每个保留关键字都必须是大…

WSDM 2024 | LLMs辅助基于内容的推荐系统增强BPR训练数据

本文提出了一种简单而有效的基于LLMs的图数据增强策略&#xff0c;称为LLMRec&#xff0c;以增强基于内容的推荐系统。LLMRec包含三种数据增强策略和两种去噪策略。数据增强策略包括从文本自然语言的角度挖掘潜在的协同信号, 构建用户画像(LLM-based), 并强化item side informa…

Adobe Illustrator绘图解决卡顿问题

最近在用AI做矢量图&#xff0c;但是遇到了一个很难搞的问题&#xff0c;当我们需要分辨率较高的图片的时候&#xff0c;Python用Matplotlib生成的pdf时dpi参数会设置为600及以上&#xff0c;但是样子的话就造成了pdf文件过大以及AI卡顿&#xff0c;比如&#xff0c;下午生成的…

解码 SQL:深入探索 Antlr4 语法解析器背后的奥秘

探寻SQL的背后机制 前言 在数据领域&#xff0c;SQL&#xff08;Structured Query Language&#xff09;是一门广泛使用的语言&#xff0c;用于查询和处理数据。你可能已经使用过诸如MySQL、Hive、ClickHouse、Doris、Spark和Flink等工具来编写SQL查询。 每一种框架都提供了…

F22服装管理软件系统 前台任意文件上传漏洞复现

0x01 产品简介 F22服装管理软件系统是广州锦铭泰软件科技有限公司一款专为服装行业开发的综合性管理软件。该产品旨在帮助服装企业实现全面、高效的管理&#xff0c;提升生产效率和经营效益。 0x02 漏洞概述 F22服装管理软件系统UploadHandler.ashx接口处存在任意文件上传漏洞…

实时天气(预报)API接口

实时天气预报API接口 一、实时天气(预报)API接口二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、 如何获取appKey和uid1、申请appKey:2、获取appKey和uid 四、重要说明 一、实时天气(预报)API接口 一款帮助你获取实时天气和天气预报的API接口 二、使用步…

对于 ` HttpServletResponse ` , ` HttpServletRequest `我们真的学透彻了吗

对于 **HttpServletResponse , HttpServletRequest**我们真的学透彻了吗 问题引入 PostMapping("/importTemplate") public void importTemplate(HttpServletResponse response) {ExcelUtil<SysUser> util new ExcelUtil<SysUser>(SysUser.class);uti…

RHCSA---基本命令使用

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 Linux中终端中的很多操作都是通过命令行实现的&#xff0c;最常用的输入命令的方法有以下两种。 (1).打开自带的终端&#xff0c;类似于Windows中的CMD (2).ssh远程连接&#xff0c;关于…

基于Java SSM框架实现高校二手交易平台系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现高校二手交易平台系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个高校二手交易平台&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将…

如何使用群晖Synology Office结合内网穿透实现多人远程编辑文件协同办公

使用群晖Synology Office提升生产力&#xff1a;多人同时编辑一个文件 文章目录 使用群晖Synology Office提升生产力&#xff1a;多人同时编辑一个文件本教程解决的问题是&#xff1a;1. 本地环境配置2. 制作本地分享链接3. 制作公网访问链接4. 公网ip地址访问您的分享相册5. 制…

创纪云助力客服系统:通过API和无代码开发实现与电商平台的智能集成

无缝连接电商和客服系统&#xff1a;管家婆的无代码开发解决方案 在电子商务和客户服务日新月异的发展中&#xff0c;企业面临着如何提高效率和客户满意度的挑战。江苏创纪云网络科技有限公司&#xff08;INNOVATION ERA&#xff09;推出了一款无需API开发的解决方案&#xff…

Springboot的excel导出

这里导出excel用到的是 阿里巴巴的easyexcel 1、首先导入依赖 <!--alibaba easyexcel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.6</version> </dependency> 2、…

一切为了应用!九章云极DataCanvas大模型系列成果重磅发布!

11月21日&#xff0c;「筑基赋能 智向未来」九章云极DataCanvas大模型系列成果发布会&#xff08;以下简称“发布会”&#xff09;在北京重磅召开&#xff0c;本次成果发布距离今年6月30日DataCanvas Alaya九章元识大模型公布仅4个多月&#xff0c;是九章云极DataCanvas公司大模…

如何快速上手一个自己不太熟悉的新项目?

一.熟悉新项目的步骤 第一步:了解业务 技术本身就是为了业务而服务&#xff0c;只有首先搞清楚了业务之后才真正算是步入了这个项目的大门。因此&#xff0c;要先搞清新项目&#xff1a; 是做什么的&#xff1f; 主要面向什么人群使用&#xff1f;主要提供了哪些功能&#x…