巧用“快指针”、“慢指针”

  有时候处理链表相关问题的时候,定义“快指针”和“慢指针“的方法有时候会极大地提高时间效率。下面是常见的几种使用这个方法的情况。假设不考虑异常输入的情况。

判断一个链表是否有环

  定义两个指针,快指针步长为2,慢指针步长为1.同时从链表头开始出发。如果链表中有环那么他们必然相遇。

 1 bool hasCycle(ListNode *head) {
 2     if(!head)
 3         return false;
 4     ListNode* fast = head->next;
 5     ListNode* slow = head;
 6     while(fast) {
 7         if(fast == slow)
 8             return true;
 9         if(fast->next&&fast->next->next){
10             fast = fast->next->next;
11             slow = slow->next;
12         }
13         else
14             return false;
15     }
16     return false;
17 }

  

求链表中倒数第k个结点

  假设链表长度为n,那么我们轻松得出这些结论:链表中的倒数第k个结点也就是正数第n-(k-1)个结点。所以我们只需要正向的让指针走n-k次,那么指针停留的结点便是倒数第k个结点。走完这个链表需要走的步长是n-1。

  我们定义两个指针,快指针先出发,走k-1步。此时它停在正数第k个结点上。慢指针也开始从链表头出发。两个指针步长都为1,走到快指针为NULL为止。快指针停止时他走的第二段路的长度就是慢指针的长度:(n-1)-(k-1)= n-k.根据第一段的推导可知此致慢指针的指向便是倒数第k个结点。

 1 ListNode* find(ListNode* head,int k)
 2 {
 3     if(!head)
 4         return NULL;
 5     ListNode* fast = head;
 6     ListNode* slow = head;
 7     for(int i=0;i<k-1;++)
 8         fast = fast->next;
 9     while(fast)
10     {
11         fast = fast->next;
12         slow = slow->next;
13     }
14     return slow;
15 }

求链表的中间结点

  这个比较简单。也是定义两个指针,快指针步长为2,慢指针步长为1。同时从head出发,当快指针为NULL时,慢指针就停在中间结点了。

 1 ListNode* findMid(ListNode* head)
 2 {
 3     if(!head)
 4         return NULL;
 5     ListNode* fast = head;
 6     ListNode* slow = head;
 7     while(fast = fast->next)
 8     {
 9         fast = fast->next;
10         slow = slow->next;
11     }
12     return slow;
13 }

 求环的长度

 求相遇的地点

原文地址:https://www.cnblogs.com/ittinybird/p/4539354.html