【剑指 offer】链表中环的入口结点

题目描述:

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路:

判断是否存在环:

使用追赶的方法,设定两个指针,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,遇到NULL。

找入口:

  • 当fast指针等于slow指针时,slow指针肯定还没有遍历完整个链表,而此时fast指针已经在环内循环了n圈(n>=1),假定从链表头指针开始slow走了s步,则fast走了2s步,fast所走的步数还等于s加上fast指针比slow指针在环内多走的n圈。设环长为r,则:
    2s = s + nr;
    =>s = nr;

  • 设整个链表长度为L,环的入口结点到相遇结点的距离为x, 起点到环的入口结点的距离为a.

    a + x = nr;
    => a + x = (n-1)r + L - a;
    => a = (n-1)r + (L - a - x);
    => 链表的头结点到环入口结点的距离等于n-1圈环的长度+相遇点到环入口结点的距离。

  • 于是,当我们在链表头部和相遇处分别设一指针,每次各走一步,则两指针必定相遇,且相遇的第一个结点即为环的入口结点。

代码:

找了半个点bug,发现初始化时,slow和fast指针就都指向头结点,第一个循环的退出条件还是slow == fast。。。猪咩。

struct ListNode {
   int val;
   struct ListNode *next;
   ListNode(int x) :
       val(x), next(NULL) {
   }
};

class Solution {
public:
   ListNode* EntryNodeOfLoop(ListNode* pHead) {
       if (pHead == NULL || pHead->next == NULL || pHead->next->next == NULL) return NULL;
       ListNode* slow = pHead->next;
       ListNode* fast = pHead->next->next;

       while(slow != fast && fast != NULL && fast->next->next != NULL) {
           slow = slow->next;
           fast = fast->next->next;
       }

       if (fast == NULL) return NULL;

       slow = pHead;
       while(slow != fast) {
           slow = slow->next;
           fast = fast->next;
       }
       return slow;
   }
};

今天又结束了。。。。

猜你喜欢

转载自blog.csdn.net/iCode_girl/article/details/88384160