剑指offer55_链表中环的入口结点_题解

链表中环的入口结点

题目描述

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

分析

方案一:双指针法

算法流程:

  1. 双指针第一次相遇:设两指针 \(pslow\)\(pfast\) 指向链表头部 \(phead\)\(pfast\) 每轮走 \(1\) 步,\(pslow\) 每轮走 \(1\)
    1. 第一种结果:\(pfast\) 走过链表末端,说明链表无环,直接返回 \(null\)
    2. 第二种结果:\(pfast == pslow\) 时,两指针在环中 第一次相遇
      1. \(pslow\) 指针位置不变,将 \(pfast\) 指针重新指向链表头部结点 \(phead\)\(pslow\)\(pfast\) 同时每轮往前走 \(1\)
      2. \(pfast==pslow\) 时,两指针第二次相遇,并同时指向链表环入口,返回 \(pslow\) 指针指向的结点

代码

/*
1.时间复杂度:O(n)
2.空间复杂度:O(1)
*/
class Solution
{
public:
    ListNode *EntryNodeOfLoop(ListNode *pHead)
    {
        ListNode *pslow = pHead, *pfast = pHead;
        while (pfast && pfast->next)
        {
            pslow = pslow->next;
            pfast = pfast->next->next;
            //快慢指针相遇
            if (pslow == pfast)
            {
                pslow = pHead;
                while (pslow != pfast)
                {
                    pslow = pslow->next;
                    pfast = pfast->next;
                }
                return pslow;
            }
        }
        return NULL;
    }
};

方法二:哈希

算法流程:

  1. 初始化 \(st\) 集合用于存储单链表的每个结点
  2. 遍历单链表的每个结点
    1. 如果当前结点没有出现在 \(st\) 集合中,则将该结点添加到 \(st\) 集合中
    2. 否则,则代表该结点被重复遍历,当前结点就是环的入口结点,返回该节点
  3. 遍历完成,返回 \(NULL\)
/*
1.时间复杂度:O(n)
2.空间复杂度:O(n)
最坏情况下,单链表的所有结点都存入set
*/
class Solution
{
public:
    ListNode *EntryNodeOfLoop(ListNode *pHead)
    {
        unordered_set<ListNode *> st;
        while (pHead)
        {
            if (st.find(pHead) == st.end())
            {
                st.insert(pHead);
                pHead = pHead->next;
            }
            else
            {
                return pHead;
            }
        }
        return nullptr;
    }
};
posted @ 2021-02-25 12:24  RiverCold  阅读(24)  评论(0编辑  收藏  举报