Java判断单链表是否有环

判断单链表是否有环

问题:判断单链表是否有环;若有环,找出进入环的第一个节点;

问题一:判断单链表是否有环
方法一,用一个集合记录以访问过的节点

遍历单链表;将经过的节点都做标记,这里采用的方法是将自己遍历的节点都放入集合Collection visited中,对每个节点都判定是否在集合中出现过,也就是是否曾经访问过。若出现重复访问,则判定有环。
空间复杂度 : O(n)
时间复杂度 : O(n^2)

    private static boolean methodSecond(Node head) {
        ArrayList visited = new ArrayList();
        while(head != null){

            if( visited.contains(head)){
                return true;
            }
            visited.add(head);
            head = head.next;
        }
        return false;
    }
方法二,快慢指针法:

定义快慢两个指针fast和slow,快指针一次移动两个节点,慢指针一次移动一个节点,从表头开始遍历链表。分为两种情况:
1.如果有环,快慢指针会在环中会和,然后停止遍历。
2.如果没有环,快慢指针会遍历到链表结尾的空节点,然后停止遍历。

问:若有环,为什么快慢指针一定会相遇?

在这里插入图片描述
假定有a个环外节点,r个环内节点
当slow指针进入环中的时候,fast指针必定已经在环中了。
此时不妨设,fast指在距离slow指针k个位置。
若slow指针走了x步之后两指针恰好相遇则需要:
存在一个正整数N,使得 (0+x) + N *r= (k+2x);
N=(k+x)/r;
很显然当x等于r-k的的时候,N=1;这时候两者会相遇。
所以slow指针和fast指针必定会相遇。

此时的时间复杂度为O(a+x)

    private static boolean thridMethod(Node head) {
        Node slow = head;
        Node fast = head;
        do{
            if(fast == null || fast.next==null){
                //没有环
                return false;
            }
            slow = slow.next;
            fast =fast.next.next;
        }while(fast != slow);
        return true;
    }
问:步长为何取2,能否取3,4,5,6,7?

设步长是len
若slow指针走了x步之后两指针恰好相遇则需要:
存在一个正整数N,使得 (0+x) + N r= (k+ lenx);
N = ((len-1)* x +k) /r;
将对应的步长为len,和k,r带入上式,若存在对应的正整数x与N,则就有能够判定有环。
当len =2 时就会一定存在,对应的一组整数值。

问题二:若有环,找出进入环的第一个节点
方法一,用一个集合记录以访问过的节点
private static Node hasCircle(Node head) {
        Collection visited = new ArrayList();
        Node node=head;
        while(node != null){
            if(visited.contains(node)){
                return node;
            }
            ((ArrayList) visited).add(node);
            node = node.next;
        }
        return null;
    }
方法二,快慢指针法:
    环外节点a个,环内节点r个;
     如果存在环,则快慢指针会在环内相遇;
     环内节点从0开始编号,若快慢指针在x相遇
    此时慢指针走了 a+x+nr
    此时快指针走了 a+x+mr = 2*(a+x+nr)
     a+x = (m-2n)r
    将快指针重置为head;和此时slow指向两者重合的编号为x的环内节点
    两指针都共同向后移一位,直至两指针再次相等
     (此时有slow指针在x处,因为a+x = kr,再走a步,相当于又走了k个圈自然就到了环的第一个节点)
    同理此时快指针也走a步,此时fast才会刚刚好进入环中,此时fast与slow才会第二次相遇
    两者都指向的节点,即为初始节点。
    private static Node secondHasCircle(Node head){
        Node slow = head;
        Node fast = head;
        do {
            if(fast==null || fast.next == null){
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
        }while(slow != fast);
        fast = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值