剑指offer 编程题(53):链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。

断链法
时间复杂度为O(n)

两个指针,一个在前面,另一个紧邻着这个指针,在后面。
两个指针同时向前移动,每移动一次,前面的指针的next指向NULL。
也就是说:访问过的节点都断开,最后到达的那个节点一定是尾节点的下一个,
也就是循环的第一个。
这时候已经是第二次访问循环的第一节点了,第一次访问的时候我们已经让它指向了NULL,
所以到这结束。

但是这种方法修改了链表的指向

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

        ListNode* previous = pHead;
        ListNode* current = pHead->next;
        while (current != NULL)
        {
            previous->next = NULL;
            previous = current;
            current = current->next;
        }

        return previous;
    }
};

快慢指针法
如果存在环,找到环的起始结点
当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圈环的长度+相遇点到环入口结点的距离,于是,当我们在链表头部和相遇处分别设一指针,每次各走一步,则两指针必定相遇,且相遇的第一个结点即为环的入口结点

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(!pHead || !pHead->next) return NULL;
        ListNode* fast = pHead;
        ListNode* slow = pHead;
       while(fast && slow){
            slow =slow->next;
            fast = fast->next->next;
            if(slow == fast)
                break;
        }
        slow =  pHead;
        while(fast != slow)
        {
            fast = fast->next;
            slow = slow->next;
        }
        return  slow;
    }
};
链接:https://www.nowcoder.com/questionTerminal/253d2c59ec3e4bc68da16833f79a38e4
来源:牛客网

class Solution
{
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL)
            return NULL;
        ListNode* pNode = pHead;
        vector<ListNode*> count;     //记录节点
        while(pNode)
            {
            //如果当前节点非空
            count.push_back(pNode);
            pNode = pNode->next;
           //判断下一个节点是否已经访问过
            if(find(count.begin(),count.end(),pNode) != count.end())
                return pNode;
        }
        return NULL;
    }
};
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL)return NULL;
        vector<ListNode*> visited;
        ListNode *p = pHead;
        while(p)
        {
            auto it = find(visited.begin(), visited.end(),p);
            if(it != visited.end() && p == *it)return p;
            visited.push_back(p);
            p = p -> next;
        }
        return NULL;
    }
};
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL || pHead->next == NULL )return NULL;
        vector<ListNode*> v;
        ListNode *p = pHead;
        while(p && (count(v.begin(),v.end(),p) == 0))
        {
             v.push_back(p);
             p = p -> next;
        }
        return p;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值