【算法萌新闯力扣】:环形链表及环形链表II

    力扣题目:环形链表及环形链表II

开篇

  今天是备战蓝桥杯的第26天和算法村开营第4天。挑选了链表的黄金关卡与大家分享。

题目一:环形链表

题目链接: 141.环形链表

题目描述在这里插入图片描述

方法一、哈希表

判断是否有环,可以利用哈希表,遍历的时候把节点放进去。当有节点在哈希表出现过时,证明存在环

public ListNode detectCycle(ListNode head){
   
ListNode pos = head;
Set<ListNode>visited = new HashSet<>();
while (pos =! null){
   
	if (visited.contains(pos)) return pos;
	else visited.add(pos);
	pos pos.next;
}
return null;
}

方法二、快慢指针

如果只用O(1)的空间,有没有其他方法?
快慢指针!这是判断是否有环最有效的方法。慢指针一次走一步,快指针一次走两步。如果快指针能走到表尾,则没有环。否则,快慢指针在环中绕圈的时候总会碰到一起。两者相碰作为判定存在环的条件

public boolean hasCycle(ListNode head){
   
if (head == null || head.next == null) return false;
ListNode fast = head, slow = head;
while(fast != null & fast.next != null){
   
	fast = fast.next.next;
	slow = slow.next;
	if (fast==slow)
		return true;
}
return false;
}

题目二:环形链表II

题目链接: 142.环形链表II

与上一题只有返回的内容不同
在这里插入图片描述

方法一、哈希表

可以利用哈希表,遍历的时候把节点放进去。当有节点在哈希表出现过时,该结点就是环的入口

public class Solution {
   
	public ListNode detectCycle(ListNode head) {
   
		ListNode node =head;
		Set<ListNode> set = new HashSet();
		while(node != null){
   
			if(set.contains(node)) return node;
			set.add(node);
			node = node.next;
		}
		return null;
	}
}

方法二、快慢指针(重点)

  这里的问题是如果知道了一定有入口,那么如何确定入口的位置呢?方法非常简单,但是要理解清楚有些难度。
  结论:先按照上面快慢方式寻找到相遇的位置(假设如下图中Z),然后将两指针分别放在链表头(X)和相遇位置(Z),并改为相同速度推进,则两
指针在环开始位置相遇(Y)
image.png

推导过程

1.假设一圈就遇到:
为了便于理解,我们首先假定快指针在第二次进入环的时候就相遇了.
此时的过程是:
(1)找环中相汇点。分别用fast、slow表示快慢指针,slow每次走一步,fast就走两步,直到在环中的某个位置相会,假如是图中的Z。
(2)第一次相遇:
那么我们可以知道fast指针走了a+b+c+b步,
slow指针走了a+b步
那么:2*(a+b)=a+b+c+b
所以a=c因此此时让slow从Z继续向前走,fast回到起点,两个同时开始走(两个每次都走一步),一次走一步那么它们最终会相遇在y点,正是环的起始点。
2.如果多圈后相遇
设链表中环外部分的长度为a,slow指针进入环后,又走了b的距离与fast相遇。此时,fast指针已经走完了环的n圈,因此它走过的总距离为:
Fast:a+n(b+c)+b=a+(n+1)b+nc
根据题意,任意时刻,fast指针走过的距离都为slow指针的2倍。因
此,我们有:
a+(n+1)b+nc=2(a+b)
由于b+c就是环的长度,假如为len,则:
a=c+(n-1)*len
这说明什么呢?说明相遇的时候快指针在环里已经转了(n-1)圈,如果
n==1就退化成了我们上面说的一圈的场景。假如n是2,3,4呢,这只
是说明当一个指针p1重新开始从head走的时候,另一个指针p2从Z点开
始,p1、p2共速时,两者会恰好在入口处相遇,只不过p2要先在环中转n-1圈。

public class Solution {
   
	public ListNode detectCycle(ListNode head) {
   
		ListNode fast = head, slow = head;
		while(fast != null && fast.next != null){
   
			if(slow.next == fast.next.next) break;
			slow = slow.next;
			fast = fast.next.next;
		}
		if(fast == null || fast.next == null) return null;
		ListNode node1 = head, node2 = slow.next;
		while(node1 != node2){
   
			node1 = node1.next;
			node2 = node2.next;
		}
		return node1;
	}
}

结语

  如果对这道题分享对您有所帮助,点个关注,为会每天更新力扣题的分享,与大伙儿一起进步!

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-06 07:00:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-06 07:00:05       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-06 07:00:05       82 阅读
  4. Python语言-面向对象

    2023-12-06 07:00:05       91 阅读

热门阅读

  1. 企业中 Docker 的 Swarm 使用及作用详解

    2023-12-06 07:00:05       47 阅读
  2. flask-sqlalchemy的配置、字段说明

    2023-12-06 07:00:05       63 阅读
  3. AIGC: 关于ChatGPT中token和tiktoken工具

    2023-12-06 07:00:05       108 阅读
  4. Hive的安装配置、初始化元数据、启动

    2023-12-06 07:00:05       50 阅读
  5. net6中使用MongoDB

    2023-12-06 07:00:05       74 阅读
  6. 【云备份】第三方库

    2023-12-06 07:00:05       57 阅读
  7. el-from表单实现lable字体大小改变

    2023-12-06 07:00:05       51 阅读
  8. Unix Network Programming Episode 82

    2023-12-06 07:00:05       58 阅读
  9. Unix Network Programming Episode 83

    2023-12-06 07:00:05       59 阅读