快慢指针法巧解链表中环的入口节点

问题描述分析 与 快慢指针巧解思路

1. 求链表中环的入口节点

如果一个链表中包含环,如何找出环的入口呢?
例如,在图示的链表中,环的入口节点是节点 3。

在这里插入图片描述

2. 快慢指针解题思路

解决这个问题的第一步应该是如何确定一个链表是否有环

确认链表中是否有环,我们仅仅需要两个指针,一个快指针一次遍历两格,一个满指针一次遍历一格,如果快指针能遍历到尾巴,则无环,如果快指针能追上慢指针,则有环。

_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Nob25nemlfZGFpbWE=,size_16,color_FFFFFF,t_70)

第二步是去找到环的入口

我们还是定义两个指针来解决这个问题,先定义两个指针都指向链表的头节点,如果链表的环有
n 个节点,那么快指针指向到 链表的第 n+1 个节点(保持 快慢指针之间的距离为n-1(不计算快慢指针的指向的两个节点)),慢指针指向头节点,之后判断是否相等,所指节点相等则 该节点是入口,反之快慢指针继续逐步遍历。

在这里插入图片描述

这时我们会发现:我们怎么知道 链表的环 有几个节点呢?

哈哈,我们可以使用暂停法,就是说我们第一步确认链表有环后,快指针暂停,慢指针逐步递增,这时计数器 +1 ,直到慢指针追上快指针,就能知道环的节点个数。


快慢指针解题代码

链表节点定义:

struct ListNode{
  int       m_nValue;
  ListNode* m_pNext;
}

声明解题函数:

ListNode* MeetingNode(ListNode* pHead);   //第一步判断是否有环以及得到相遇节点
ListNode* EntryNodeOfLoop(ListNode* pHead);

保证代码的鲁棒性,注重防御性编程,加油!

功能测试: (链表中包含或者不包含环;链表中有多个或者只有一个节点)
特殊输入测试:(链表头节点为 nullptr 节点)

ListNode* MeetingNode(ListNode* pHead){   //判断是否有环以及得到相遇节点
      if(!pHead)
         return nullptr;
      ListNode* pSlow = pHead;
      ListNode* pQuick = pHead;
      while(pQuick->next!=nullptr){
         pQuick = pQuick->m_pNext;
         if(pQuick->next != nullptr)
           pQuick = pQuick->m_pNext;
          else
             break;
         pSlow = pSlow ->next;
         if(pSlow == pQuick)
            return pQuick;
      }
      return nullptr;
}

ListNode* EntryNodeOfLoop(ListNode* pHead){{
    auto meetingNode = MeetingNode(pHead);
    if(meetingNode == nullptr) 
       return nullptr;

    //第二步 统计环节点个数
    ListNode* pNode1 = meetingNode;
    int numsOfLoop = 0;
    while(pNode1 != meetingNode){
         pNode1 = pNode->m_pNext;
         ++ numsOfLoop;
    }
    
    //快慢指针找寻 链表环开始节点。
    pNode1 = pHead;
    for(int i=0;i!= numsOfLoop; ++i){
         pNode1 = pNode1->m_next;
    }
    ListNode* pNode2 = pHead;
    while(pNode2 != pNode1){
          pNode1 =pNode1->m_pNext;
          pNode2 =pNode2->m_pNext;
   }
   return pNode2;
}



猜你喜欢

转载自blog.csdn.net/chongzi_daima/article/details/105837620
今日推荐