List——顺序表链表OJ
创始人
2024-03-24 15:45:59
0

文章目录

  • 前言
  • 一、合并两个有序链表
  • 二、使用顺序表实现“杨辉三角”
  • 三、环形链表
  • 四、环形链表Ⅱ
  • 总结


前言

上两篇内容,对链表和顺序表进行了讲解并手动实现了自己的顺序表和链表,本篇文章将结合LeetCode上的OJ题,进行具体的使用以熟悉其中的方法和使用细节。


一、合并两个有序链表

题目链接:Leetcode.21题

在这里插入图片描述

有序、链表这是题目中已经说明的,具体思路是我们创建一个新的头结点用来保存合并后的链表。分别遍历两个链表的头节点,将较小的头结点链接在新的链表后 然后头节点后移继续比较,直到一个链表为空(当有一个链表为空时,只需要将另一个链表剩余部分全部连接在答案链表之后)。

代码实现:

public class Leetcode21_MergeTwoList {public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode head1=list1;ListNode head2=list2;//定义一个储存答案的头结点ListNode ansHead= new ListNode();ListNode ansLast=ansHead;  //尾节点while (head1!=null&&head2!=null) {//比较两个链表头结点的大小if (head1.val < head2.val) {//先将待连接的头节点保存下来ListNode cur = head1;//链表1头节点后移head1 = head1.next;//将之前保存的头节点连接到结果链表中ansLast.next = cur;//更新结果链表的尾节点ansLast = cur;} else {ListNode cur = head2;head2 = head2.next;ansLast.next = cur;ansLast = cur;}}if(head1!=null){ansLast.next=head1;}else {ansLast.next=head2;}return ansHead.next;}}

测试代码正确性:

//测试代码正确性public static void main(String[] args) {ListNode listN1 = new ListNode(100);ListNode listN2 = new ListNode(200);ListNode listN3 = new ListNode(300);listN1.next = listN2;listN2.next = listN3;listN3.next=null;ListNode listN4 = new ListNode(100);ListNode listN5 = new ListNode(200);ListNode listN6 = new ListNode(300);listN4.next=listN5;listN5.next=listN6;listN6.next=null;ListNode ans=mergeTwoLists(listN1,listN4);ListNode cur=ans;while (cur!=null){System.out.print(cur.val+" ");cur=cur.next;}}

运行结果:

在这里插入图片描述

二、使用顺序表实现“杨辉三角”

题目链接:Leetcode.118题
在这里插入图片描述

这道题,我们需要使用List接口下的ArrayList。我们可以创建一个线性表,线性表中的每一个元素也是一个线性表,每个线性表是一个ArrayList,存储的是该行对应的元素。需要特殊处理的是三角形的前两行,第三行开始只需要首尾填1,其他使用循环结构从上一行取元素加和即可。

代码实现:

class Solution {public static List> generate(int num) {List> ans = new ArrayList<>();//零行不做任何处理  直接返回if (num == 0) {return ans;}//走到这儿,说明至少有一行,先添加一行进去ans.add(new ArrayList<>());//对第一行的顺序表添加元素1ans.get(0).add(1);//判断是不是只有一行,若是  返回if (num == 1) {return ans;}//走到这儿说明至少有两行 再添加一行(一个顺序表)进去ans.add(new ArrayList<>());//处理第二行元素ans.get(1).add(1);ans.get(1).add(1);//判断是否只有两行if (num == 2) {return ans;}//走到这儿  就有规律可循了  第三行之后每一行只有首尾是1,其他元素根据上一行得到for (int i = 3; i <= num; i++) {//每走一趟循环  添加一行进去List cur = new ArrayList<>();ans.add(cur);ans.get(i - 1).add(1);   //这一行的首元素//循环体中对每一行除首尾之外的元素进行处理for (int j = 0; j < i - 2; j++) {int first = ans.get(i - 2).get(j); //获取上一行第j个元素int second = ans.get(i - 2).get(j + 1);//上一行第j+1个元素int e = first + second; //求和ans.get(i - 1).add(e);  //添加到这一行的顺序表中}ans.get(i - 1).add(1);  //这一行的尾元素}return ans;}
}

测试代码正确性:

public static void main(String[] args) throws InterruptedException {System.out.println(Leetcode118_Generate.generate(6));}

运行结果:

在这里插入图片描述

三、环形链表

题目链接:Leetcode.141题

在这里插入图片描述

思路一:哈希表,这道题比较容易想到的一个思路是,我们可以遍历这条链表,每次遍历时判断该节点是否被访问过。可以使用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。但是哈希表方法还没总结,因此我们使用一个更简单的方法。

思路二:快慢指针,此方法为Floyd判圈算法(又称龟兔赛跑算法),假想乌龟和兔子同时从同一起点在链表上移动,如果链表上没有环,那么兔子将一直处于乌龟的前方;若该链表中有环,那么「兔子」会先于「乌龟」进入环,并且一直在环内移动。等到「乌龟」进入环时,由于「兔子」的速度快,它一定会在某个时刻与乌龟相遇,即套了「乌龟」若干圈。

我们可以根据上述思路来解决本题。具体地,我们定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,块慢指针都在位置 head,这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。

代码实现:

public boolean hasCycle(ListNode head){//先处理空链表和只有一个结点的情况if(head==null){return false;}if(head.next==null){return false;}//定义快慢指针ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){   //fast.next!=null  这一句很关键  没有的话会报空指针异常~fast=fast.next.next;  //没有fast.next!=null这个条件的话  这里会空指针异常slow=slow.next;if(fast==slow){return true;}}return false;}

测试代码正确性:

public static void main(String[] args) {ListNode listN1 = new ListNode(100);ListNode listN2 = new ListNode(200);ListNode listN3 = new ListNode(300);listN1.next = listN2;listN2.next = listN3;listN3.next = listN1;System.out.println(hasCycle(listN1));}

在这里插入图片描述

四、环形链表Ⅱ

题目链接:Leetcode.142题

在这里插入图片描述
与上一题不同的是,上一题只需要判断链表中有没有环,此题需要找到并返回环的入口节点,难点在于如何找到?

判断是否有环上面已经讲过了,此时找环的入口:
假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。 如图所示:

在这里插入图片描述
那么相遇时: slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。
因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2: (x + y) * 2 = x + y + n (y + z)

两边消掉一个(x+y): x + y = n (y + z)

因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。

所以要求x ,将x单独放在左面:x = n (y + z) - y ,

再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z 注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。

这个公式说明什么呢?

先拿n为1的情况来举例,意味着fast指针在环形里转了一圈之后,就遇到了 slow指针了。

当 n为1的时候,公式就化解为 x = z,

这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。

也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。

让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。

那么 n如果大于1是什么情况呢,就是fast指针在环形转n圈之后才遇到 slow指针。

其实这种情况和n为1的时候 效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

这样我们只需要对上面的代码稍作修改,就可以AC这道题了!

代码如下:

public ListNode detectCycle(ListNode head){if(head==null){return null;}if(head.next==null) {return null;}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;}}//运行到此处 说明存在环,快指针比慢指针多走了 n倍的环的长度//如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=x+n(y+z)(先走 x 步到入口节点,之后每绕 1 圈环( y+z 步)都会再次到入口节点)。//而目前,slow 指针走过的步数为 n(y+z) 步。因此,我们只要想办法让 slow 再走 x 步停下来,就可以到环的入口。//但是我们不知道 x 的值,该怎么办?依然是使用双指针法。我们构建一个指针,此指针需要有以下性质:此指针和slow 一起向前走 x 步后,两者在入口节点重合。那么从哪里走到入口节点需要 x 步?答案是链表头部headfast=head;while (fast!=slow){slow=slow.next;fast=fast.next;}return slow;}

验证代码正确性:

public static void main(String[] args) {//listN1是头节点也是链表环的入口ListNode listN1 = new ListNode(100);ListNode listN2 = new ListNode(200);ListNode listN3 = new ListNode(300);listN1.next = listN2;listN2.next = listN3;listN3.next = listN1;System.out.println(detectCycle(listN1).val);//输出入口结点的值}

在这里插入图片描述


总结

本篇博客通过四道力扣题对顺序表和链表的使用以及其具体实现了ArrayList、LinkedList进行了使用,后面还会更新更多的Leetcode题~ 感兴趣的老铁店点关注不迷路 谢谢支持!

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...