[LeetCode] 141. Linked List Cycle

32 篇文章 0 订阅
19 篇文章 0 订阅

原题链接: https://leetcode.com/problems/linked-list-cycle/

1. 题目介绍

Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Follow up:
Can you solve it using O(1) (i.e. constant) memory?

给定一个链表,判断该链表中是否有环。
使用整数 pos 表示链表的最后一个节点指向的节点。pos 取值范围是(0,indexed)indexed是链表节点的索引序号。当pos 为 -1 的时候,表示链表最后的节点没有指向任何节点,也就是不含有环。

做题的时候,只会给出链表的头节点,不会给出pos。

可以在O(1)空间复杂度下实现吗?

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.

在这里插入图片描述
Example 2:

Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.

在这里插入图片描述
Example 3:

Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.

在这里插入图片描述

2. 解题思路

2.1 使用HashSet

遍历链表,使用HashSet存储所有被遍历过的节点。在遍历的过程中,如果遇到的节点已经存在于HashSet中,那么就肯定有环路了,返回true。当遍历完所有节点后,仍然没有发现重复的HahsSet,那就返回false。

时间复杂度:O(n) , 对于有 n 个元素的链表,访问每个元素最多一次,所以遍历链表最多访问n次。添加一个节点到HashSet中只需要花费 O(1) 的时间。

空间复杂度:O(n), 空间复杂度取决于添加到哈希表中的元素数目,最多可以添加 n 个元素。

实现代码

/**
 * 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) {
		HashSet<ListNode> set = new HashSet<>();
		ListNode assist = new ListNode(0);
		assist.next = head;
		
		ListNode cur = assist;
		while(cur.next != null){
			if(set.contains(cur.next) ){
				return true;
			}else{
				set.add(cur.next);
				cur = cur.next;
			}
		}
    	return false; 
    }
}

2.2 双指针法

这个方法是LeeCode的题解上给出的,通过双指针法可以真正实现空间复杂度为O(1),时间复杂度为O(n)
如果觉得英文不好理解,建议可以直接去LeetCode中文版中看 https://leetcode-cn.com/problems/linked-list-cycle/solution/ 的解释,题解说得非常到位。下面我将它的解释稍微修改下,写在下面。

想象一下,两名运动员以不同的速度在环形赛道上跑步会发生什么?跑得快的人最终会追上跑得慢的人。

通过使用具有不同速度的快、慢两个指针遍历链表,空间复杂度可以被降低至 O(1)。慢指针每次移动一步,而快指针每次移动两步。

如果列表中不存在环,那么没有任何节点的 next 值为 null ,所以如果快指针发现有节点指向 null,此时我们可以返回 false。

如果列表中存在环,那我们可以把慢指针和快指针想象成两个在环形赛道上跑步的运动员(分别称之为慢跑者与快跑者)。快跑者最终一定会追上慢跑者。这是为什么呢?

考虑下面这种情况(记作情况 A) - 假如快跑者只落后慢跑者一步,也就是他们之间有1步的距离。在下一次迭代中,慢跑者向前跑1步,快跑者向前跑2步,他们之间的距离扩大为2步。如果持续跑下去,它们两个人之间的距离会不断增大。当距离达到环的长度后,两者就会相遇了。

其他情况又会怎样呢?例如,我们没有考虑快跑者在慢跑者之后两步或三步的情况。但其实不难想到,因为在多次迭代后,又会变成上面提到的情况 A。

实现代码

/**
 * 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) {
		ListNode assist = new ListNode(0);
		assist.next = head;
		
		if(assist.next == null || assist.next.next == null){
			return false;
		}
		
		ListNode slow = assist.next;
		ListNode fast = assist.next.next;
		
		while(slow != fast){
			if(fast == null || fast.next == null ){
				return false;
			}else{
				slow = slow.next;
				fast = fast.next.next;
			}
		}
    	return true; 
    }
}

3. 参考资料

https://leetcode.com/problems/linked-list-cycle/solution/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值