数据结构笔记5:环形链表的数理分析
链表OJ题:
环形链表:
使用快慢指针的方法:当慢指针和快指针相遇的时候证明链表是有环的。
证明:假设环的长度为C,入环前的长度为L。
假设fast在环内走了n圈。
当slow抵达第一个入环的节点时,fast和slow的距离为2L-n*c-L = L-n*C。
由于fast每次走两步,slow每次走一步,所以fast和slow之间的距离每次缩小一个单位。
当slow距离第一个入环的节点的距离为(n+1)*C-L时,fast和slow会相遇。
环形链表2:
当fast指针和slow指针相遇时。
假设相遇位置为meet,相遇位置和入环节点的距离为L-n*C,如果meet要走L距离的话,那么就要走L-n*C(这是距离入环节点的距离) + n*C(这是绕环走一圈)= L。也就是说,当meet走L距离,肯定会停在入环节点处。
所以我们可以定义一个cur指针,从头开始走,当cur指针和meet指针相遇的时候,也就是meet走了L距离的时候,也就是停在了入环节点的位置。
我们可以进一步假设:
前面的快慢指针方法是快指针走一步而慢指针走两步,那么要是快指针走三步而慢指针走一步呢?快慢指针判断是否有环还有效吗?
如果是fast走三步而slow走两步,第一个入环节点到fast的距离为(3L-L-n*C)也就是2L-n*C,fast到第一个入环节点的距离为(n+1)*C-2L。
而fast和slow的距离每次都会缩小两格,所以当(n+1)*C-2L 的值为偶数的时候,fast和slow可以直接相遇,而当(n+1)*C-2L为奇数的时候,fast和slow不会直接相遇,而是错过一格。
那时fast和slow的距离就变成了C-1.
如果C-1还是奇数的话,那下次fast和slow的距离也依旧是C-1。
但是这种可能存在吗?
当C-1是奇数时,说明C是偶数,前面说假设(n+1)*C-2L为奇数,当C是偶数时,(n+1)*C - 2L就不可能是奇数。
也就是说,要么(n+1)*C-2L为奇数,而C不为偶数,还是会相遇。
要么(n+1)*C-2L为偶数,直接相遇。
所以fast走三步slow走一步的这种设计,同样可以通过相遇来判断是否是带环链表。
环形链表:
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {ListNode* fast = head;ListNode* slow = head;while(fast != NULL && fast->next != NULL){fast = fast->next->next;slow = slow->next;if(fast == slow){return true;}}return false;
}
环形链表2:
typedef struct ListNode ListNode;ListNode* hascycle(ListNode* head){ListNode* fast = head;ListNode* slow = head;while(fast != NULL && fast->next != NULL){fast = fast->next->next;slow = slow->next;if(fast == slow)return fast;}return NULL;}
struct ListNode *detectCycle(struct ListNode *head) {ListNode* meet = hascycle(head);if(meet == NULL){return NULL;}ListNode * cur = head;while(cur != meet){cur = cur->next;meet = meet->next;}return cur;
}