zoukankan      html  css  js  c++  java
  • 剑指:链表中环的入口结点

    题目描述

    给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null

     

    解法一:借助HashSet结构

     逐个节点对象加入set中,如果已存在,则说明是入口结点。

    /*
     public class ListNode {
        int val;
        ListNode next = null;
    
        ListNode(int val) {
            this.val = val;
        }
    }
    */
    
    import java.util.HashSet;
    
    public class Solution {
    
        public ListNode EntryNodeOfLoop(ListNode pHead)
        {
            HashSet<ListNode> set = new HashSet<ListNode>();
    
            while (pHead != null) {
                if (!set.add(pHead)) {
                   return pHead;
                }
                pHead = pHead.next;
            }
    
            return null;
        }
    }

    时间复杂度 O(nlogn),insert和find/contains的时间复杂度皆可近似看为O(logn)级,如果遍历一遍并且对每一个节点进行查重,插入处理,那么总的时间复杂度为O(nlogn)。

    空间复杂度 O(n)

    解法二:

    首先有两个结论:

    1、设置快慢指针,假如有环,他们最后一定相遇。
    2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇于环入口。
     
    证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。
    证明结论2:
    设:
    链表头到环入口长度为--a
    环入口到相遇点长度为--b
    相遇点到环入口长度为--c

    则:相遇时
    快指针路程=a+(b+c)k+b ,k>=1  其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。
    慢指针路程=a+b
    快指针走的路程是慢指针的两倍(快走2,慢走1),所以:
    (a+b)*2=a+(b+c)k+b
    化简可得:
    a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。
     
     
    实现:
    • 先利用快慢指针。若能相遇,说明存在环,且相遇点一定是在环上;若没有相遇,说明不存在环,返回 null
    • 固定当前相遇点,用一个指针继续走,同时累积结点数。计算出环的结点个数 cnt
    • 指针 p1 先走 cnt 步,p2 指向链表头部,之后 p1,p2 同时走,相遇时,相遇点一定是在环的入口处。因为 p1 比 p2 多走了环的一圈。
    链接:https://www.nowcoder.com/questionTerminal/253d2c59ec3e4bc68da16833f79a38e4?f=discussion
    来源:牛客网
    
    public class Solution {
     
        public ListNode EntryNodeOfLoop(ListNode pHead)
        {
            ListNode fast=pHead;
            ListNode low=pHead;
            while(fast!=null&&fast.next!=null){
                fast=fast.next.next;
                low=low.next;
                if(fast==low)
                    break;
            }
            if(fast==null||fast.next==null)
                return null;
            low=pHead;
            while(fast!=low){
                fast=fast.next;
                low=low.next;
            }
            return low;
        }
    }
  • 相关阅读:
    Unity错误-(Android build error) Can not sign application Unable to sign application; please provide passwords!
    C#WCF中传输List对象
    抓包工具Omnipeek,Wireshark
    Ubuntu18+.netcore+Nginx+Supervisor部署ASP.NET项目
    3D成像技术
    3D显示技术
    学习模电与数电
    【Java123】解决PKIX path building failed / unable to find valid certification path to requested target
    【Python123】Introduction
    【WebConsole123】练习案例之浏览器访问服务器shell
  • 原文地址:https://www.cnblogs.com/lisen10/p/11568206.html
Copyright © 2011-2022 走看看