1. 程式人生 > 實用技巧 >連結串列判斷是否有環,如有,找入環節點

連結串列判斷是否有環,如有,找入環節點

一條連結串列如何判斷是否有環?若是有環那怎麼找到連結串列環的入口?

解決思路

  • 先判斷是否有環

思路:用快慢兩個指標分別從連結串列頭開始,慢指標一次走一個節點,快指標一次走兩個節點next -> next,這樣如果有環那快指標務必會跑到慢指標後面,隨即兩者之間的距離一次會縮小一步,最終相遇。若是未相遇且快指標的 next 為 null,則說明連結串列無環。

  • 若是有環怎麼找到環入口

  如果快慢指標相遇,說明有環,假設起點到入環節點的距離為L,入環節點到相遇節點的距離為x,環的周長為L,根據速度可推出下面關係見

 假設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; } };

判斷是否有環+尋找入環節點

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;
    }
};