链表判断是否有环,如有,找入环节点

一条链表如何判断是否有环?若是有环那怎么找到链表环的入口?

解决思路

  • 先判断是否有环

思路: 用快慢两个指针分别从链表头开始,慢指针一次走一个节点,快指针一次走两个节点next -> next,这样如果有环那快指针务必会跑到慢指针后面,随即两者之间的距离一次会缩小一步,最终相遇。若是未相遇且快指针的 next 为 null,则说明链表无环。

  • 若是有环怎么找到环入口

  如果快慢指针相遇,说明有环,假设起点到入环节点的距离为L,入环节点到相遇节点的距离为x,环的周长为H,根据速度可推出下面关系见

 

 

 

 

 

 假设n=1,也就是当快指针再走第二圈的时候和慢指针相遇,他们的关系为L=H - x

也就是说,如果这个时候有一个指针temp从起点开始走,慢指针low 从相遇的地方开始走,当temp指针与low相遇的位置就是入环节点

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};
// 快慢指针
class Solution {
public:
    bool hasCycle(ListNode *head) {
        //空链表或只有一个节点的链表不算环
        if (head == NULL || head->next == NULL)  
            return false;
        ListNode *fast = head->next;
        ListNode *slow = head;
        while (fast != slow) {
            if (fast->next == NULL || fast->next->next == NULL)
                return false;
            fast = fast->next->next;
            slow = slow->next;
        }
        return true;
    }
};
//哈希表
class Solution {
public:
    bool hasCycle(ListNode *head) {
        unordered_map<ListNode*, int>mp;

        while (head != NULL) {
            mp[head]++;
            if (mp[head] > 1)
                return true;
            head = head->next;
        }
        return false;
    }
};

 

判断是否有环+寻找入环节点

参考:https://juejin.cn/post/7188902509996408893

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head, *fast = head, *p = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)            //如果链表存在环
            {
                while(p != slow)
                {
                    p = p->next;
                    slow = slow->next;
                }
                return p;
            }
        }
        return NULL;
    }
};

 

go实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    fast:=head
    slow:=head
    for fast!=nil&&fast.Next!=nil{
        fast=fast.Next.Next
        slow=slow.Next
        if slow==fast{ //没有环就不会相遇,这里找到快慢指针相遇的位置
            for head!=slow{  //L=H-x  ,L是头结点到入环节点的距离,H是环的周长,x是入环节点到相遇节点的距离
                head=head.Next
                slow=slow.Next
            }
            return head
        }
    }
    return nil
}

 

posted @ 2020-08-04 20:36  知道了呀~  阅读(667)  评论(0编辑  收藏  举报