剑指offer编程题—链表中环的入口


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

解题思路
使用C++中的关联容器set,set 中插入单个元素的 insert 成员函数的返回值是 pair 模板类对象,假设返回结果为x,如果 x.second 为 true,则说明插入成功,此时 x.first 就是指向被插入元素的迭代器;如果 x.second 为 false,则说明要插入的元素已在容器中,此时 x.first 就是指向原有那个元素的迭代器。
根据以上知识,可以通过遍历链表,并将遍历结点插入set关联容器中,插入失败时返回的迭代器指向的就是链表中环入口的结点。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        set s;
        pair::iterator,bool> res;
        ListNode* p=pHead;
        while(p){
            res=s.insert(p);
            if(!res.second) return *res.first;
            p=p->next;
        }
        return p;
    }
};

思路2
使用快指针、慢指针,假设已知链表中的环由n个结点围成,令快指针比慢指针先走n个结点,则当快慢指针相遇时,相遇结点就是环的入口。
根据以上思路还可以进一步简化:

  1. 令快慢指针都指向链表首元结点;
  2. 规定快指针每次走两步,慢指针每次走一步;
  3. 当快指针与慢指针第一次相遇时,可以总结两点信息:
    1)此时快指针比慢指针多走了一个环;
    2)快指针走的路程是慢指针所走路程的两倍,因为快指针每次走两步,慢指针每次只走一步;
    综上两点易得,此时慢指针所走路程就是一个环的长度;
  4. 重新令慢指针指向链表首元结点,快指针不动(此时相当于快指针比慢指针先走了一个环的长度);
  5. 快慢指针每次只向前移动一步,二者相遇的结点就是环入口结点。
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead==NULL) return NULL;
        ListNode* pslow=pHead->next;
        ListNode* pfast=pHead->next;
        if(pfast!=NULL) pfast=pfast->next;
        while(pslow!=pfast && pfast){
            pslow=pslow->next;
            pfast=pfast->next;
            if(pfast!=NULL) pfast=pfast->next;
        }
        if(pfast==NULL) return pfast;
        pfast=pHead;
        while(pslow!=pfast){
            pslow=pslow->next;
            pfast=pfast->next;
        }
        return pfast;
    }
};

你可能感兴趣的:(剑指offer编程题—链表中环的入口)