设置两个指针p,q,开始时两个指针均指向head;
p每次向前移动一步,q每次移动两步;不断移动,若在移动过程中p和q重合(p == q)则说明有环(证明略)。
代码:
struct ListNode { int val; struct ListNode *next; ListNode(int x):val(x), next(NULL) {} }; bool hasCircle(ListNode *head) { if(head == NULL) return false; ListNode *p = head; ListNode *q = head; while(q != NULL && q->next != NULL) { p = p->next; q = q->next->next; if(p == q) return true; if(p == NULL || q == NULL || q->next == NULL) return false; } return false; }
若链表中有环存在,则从head处到上述p和q指针初次相遇处的节点(由p和q指向)的距离(节点数),等于环的长度(节点数)。所有找到上述p和q初次相遇的节点后,分别从head和此节点开始,每次向前一步,再一次相遇的节点便是环的入口节点(证明略)。
代码:
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { if(pHead == NULL) return NULL; ListNode *p = pHead; ListNode *q = pHead; while(p!=NULL && q != NULL && q->next == NULL) { p = p->next; if(q == NULL || q->next == NULL) return NULL; //无环 else q = q->next->next; if(p == q) { break; } } q = pHead; while(1) { if(p == q) return p; p = p->next; q = q->next; } return p; } };