Linked List Cycle II(LeetCode)

题目:

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:
Can you solve it without using extra space?


题目分析:题目要求检查一个链表有没有循环,有的话返回循环开始的那个节点,否则返回null,不能使用额外空间。刚开始想,有可能有多个cycles,那样会很复杂。后来仔细一想,这是一个单链表,最多只会有一个循环。想了很久这个题目,没什么头绪,因为链表可能循环,没有办法确定链表有没有终点。


思路:

不知道怎么的蹦出一个很吊的想法(可能以前在哪里见过吧,呵呵。。。不过能记得就挺叼的了,赞一个,哈哈。。。)这个想法就是,同时让两个节点遍历这个链表,一个快一个慢,如果快的和慢的能够相遇,说明有循环!有了这个想法,想一步到位,让快的和慢的相遇在循环开始的节点。发现这样很难实现。于是,退而求其次,先利用这个方法确定有没有循环,然后再找出循环开始节点在哪里。

  1. 让两个节点,一快一慢遍历链表
    • fast节点,每次移动两步;slow节点,每次移动一步;
    • 每当有节点移动,就检查fast和slow有没有相遇,有则说明有循环,推出检查
    • 同时还要检查,fast有没有走到null,如果走到null,说明没有循环,return null
    • 如果有循环,记相遇点为meetPoint
  2. 如果有循环,查找循环开始的节点
    • slow从head出发,一个个检查是否是循环开始节点
    • 对于每一个slow,fast都从meetPoint转一圈,看能不能和slow相遇
    • 如果相遇,相遇点即为循环开始点
    • 如果不相遇,说明slow所在的点还不是循环开始点,令slow=slow.next,fast再从meetPoint转一圈检查
    • 如此反复,直到找到循环开始节点




注意点:

  1. 注意使用标记 tag:...while(或者for)时,可以使用 break tag 或者 continue tag 指定跳出循环的层次
  2. 注意 do{...}while(...); 的用法




代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null){
            return null;
        }
        ListNode slow,fast,meetPoint;
        slow = fast = head;
        outer:
        while (true){
            for (int i =0; i<2; i++){
                fast = fast.next;
                if (fast == null){
                    return null;
                }
                if (fast == slow){
                    meetPoint = fast;
                    break outer;
                }
            }
            slow = slow.next;
            if (fast == slow){
                meetPoint = fast;
                break;
            }
        }
        slow = head;
        fast = meetPoint;
        while (true){
            do{
                if (fast == slow){
                    return slow;
                }
                fast = fast.next;
            }while (fast != meetPoint);
            slow = slow.next;
        }
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值