141. Linked List Cycle

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.

 

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.

 

Follow up:

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

--------------------------------------------------------------------------------------------------------------------------------

https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare

其实很多东西并不难,但是中文资料却几乎没有能说清楚的。

这道题是弗洛伊德龟兔算法:请查看上面的维基百科链接。

先声明几个变量:

u表示环的第1个元素的序号(序号从0开始)

λ表示环的长度

那么当 i>=u时,x[i] = x[i+kλ]    其中k>=0

一定存在某个时候,使得i=kλ (需满足i>=u) ,即x[i] = x[i+kλ] = x[2*i] 

(上面这种情形是一定会出现的,很容易想明白)

那么也就是说,只要存在环,就一定存在i,使得x[i] = x[2*i]

那么我们使得龟兔同时从x[0]开始,龟一次走一步,兔一次走两步,则兔所在的节点的序号是龟的两倍。当龟兔相遇时,即x[i] = x[2*i],即可判定有环。此时龟兔所在的节点一定是在环内的。

代码如下:

/**
 * 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 hare = head;
        ListNode tortoise = head;
        while(hare!=null && hare.next!=null){//
            hare = hare.next.next;
            tortoise = tortoise.next;
            if(hare==tortoise) return true;
        }
        return false;
        
    }
    

}

判定有环无环问题到这里就结束了,但是如果想知道环的入口的节点序号还需要进行以下操作:

当hare和tortoise相遇时,使:

tortoise从相遇点开始,每次走一步

hare回到链表开头,每次走一步

那么当hare到达环的入口时,hare为x[u], tortoise为x[i+u]     注意hare与tortoise的相遇点的i是满足i=kλ的,且x[i]在环内。

则x[i+u] = x[kλ+u] = x[u],即当hare到达环的入口时,tortoise也到了环的入口。

即此次的相遇点就是环的入口。

在hare从链表开头开始向前走的时候,可以记录步数来得到环的入口位置。

得到环的入口位置后,很容易得到环的长度:

从入口开始走,记录步数,当发现等于入口时即绕了一圈。

-------------------------------------------------------------------------------------------------

更新:

今天发现佛洛依德龟兔法其实就是一个追及问题。

另外,

下面再贴出使用hashset的解法(空间复杂度为O(n))

    public boolean hasCycle(ListNode head) {
        Set<ListNode> seen = new HashSet<>();
        while(head!=null){
            if(!seen.add(head)){
                return true;
            }
            head = head.next;
        }
        return false;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值