leetcode刷题_OJ 141判断链表是否有环以及环的入口

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

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

判断链表是否有环,具体分析过程可以看这篇博客,主要分析了3种方法,两种常规,一种比较巧妙。

总结一下,前两种主要是在遍历到某一节点时,对当前以及之前遍历过的节点进行检查,若发现有重复的,则说明有环。既可以浪费时间直接对当前节点之前的列表进行遍历,优点是无需另外开辟空间;也可以用一个哈希链表以节点为键值来存储遍历过的节点,访问节点时,到哈希中发现是否存在,若有,则存在环,否则将当前节点存进哈希表,这种的优点是时间上大大加快。

巧妙一点的方法:定义两个指针在一开始都指向头节点,然后设定在每一次循环里,让快的指针移动两位,慢的指针移动一位。

假如存在环,快的指针总有机会与慢的指针重合。

/**
 * 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) {
        if(head == null) return false;
        ListNode fast=head;
        ListNode slow=head;
        while(fast.next != null && fast.next.next != null){//这里很容易发生越界,坑的是我把两个.next写在了前面就会越界,写在后面就不会
            fast=fast.next.next;
            slow=slow.next;
            if(fast == slow){
                return true;
            }
        }
        return false;
    }
}

判断环的入口

一开始我傻了地以为,只要上面相遇那点就是环的入口,这个很明显就是不对的,但是我们依然可以在上面的基础上进行改进。在上面,我们可以获得相交的一点是位于环内的,那么为了求环的入口,不就是求链表与环的交点?

有了这个想法,我们可以再定义两个指针,一个指向头节点表示原链表,一个指向刚才相遇的环内的节点,当它们相等时,返回的就是环的入口。这篇博客也讲得很清楚

public class Solution {
   ListNode EntryNodeOfLoop(ListNode h){
        if(h == null || h.next == null)
            return null;
        ListNode slow = h;
        ListNode fast = h;
        while(fast != null && fast.next != null ){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                ListNode p=h;
                ListNode q=slow;//相当于让q指向了m1
                while(p != q){
                    p = p.next;
                    q = q.next;
                }
                if(p == q)
                    return q;
                }
        }
        return null;
}

猜你喜欢

转载自blog.csdn.net/cyanchen666/article/details/81868191