連結串列判斷是否有環,如有,找入環節點
阿新 • • 發佈:2020-08-04
一條連結串列如何判斷是否有環?若是有環那怎麼找到連結串列環的入口?
解決思路
- 先判斷是否有環
思路:用快慢兩個指標分別從連結串列頭開始,慢指標一次走一個節點,快指標一次走兩個節點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; } };