剑指Offer - 面试题23:链表中环的入口节点

简介: 剑指Offer - 面试题23:链表中环的入口节点

题目

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

分析

将这个问题解剖开。分为俩步

  1. 判断是否有环
  2. 有环再找入口节点


第一个问题:我们用快慢指针来判断,只要相遇就有环,快指针走到头就是没有环。


第二个问题:与剑指Offer - 面试题22:链表中倒数第K个节点第二种方法思想相似,可以先去看看这个题。我们先定义链表头到入口距离m,环的长度为n。那么可以先让快指针从头开始走环的长度n,那么快指针走到环的入口还需要走m长度。刚好此时慢指针也一起走,走到入口处相遇。比较绕建议自己画一画。


整理一下:快指针需要走m+n的长度,慢指针需要走m长度,所以让快指针先走n长度,然后快慢同时走相遇就是入口处。


在代码中我们构造了一个与上图相同的链表。

C++

#include <iostream>
using namespace std;
typedef int TElemType;//链表节点值的数据类型
struct ListNode
{
  TElemType Data;
  struct ListNode* Next;
};
ListNode* CreateList(int data)//创建节点
{
  ListNode* node = new ListNode();
  node->Data = data;
  node->Next = nullptr;
  return node;
}
void connect(ListNode* front, ListNode* rear)//连接节点
{
  front->Next = rear;
}
ListNode* EntranceNode(ListNode* pHead)//查找环入口
{
  if (nullptr == pHead)
  {
    return nullptr;
  }
  ListNode* fast = pHead;//快指针
  ListNode* slow = pHead;//慢指针
  bool sign = false;//默认无环
  //判断有无环
  while (fast->Next != nullptr && sign  == false)
  {
    fast = fast->Next->Next;
    slow = slow->Next;
    if (fast == slow)
    {
      sign = true;
    }
  }
  if (sign == false)//无环
  {
    return nullptr;
  }
  //计算环长
  int len = 0;
  do
  {
    fast = fast->Next;
    len++;
  } while (fast != slow);
  //复原指针
  fast = pHead;
  slow = pHead;
  int i = 0;
  for (i = 0; i < len; i++)//快指针先走环的长度
  {
    fast = fast->Next;
  }
  while (fast != slow)//同时走,相遇即为入口
  {
    fast = fast->Next;
    slow = slow->Next;
  }
  return fast;
}
int main()
{
  /*构造一个带环的链表*/
  ListNode* Node1 = CreateList(1);
  ListNode* Node2 = CreateList(2);
  ListNode* Node3 = CreateList(3);
  ListNode* Node4 = CreateList(4);
  ListNode* Node5 = CreateList(5);
  ListNode* Node6 = CreateList(6);
  connect(Node1, Node2);
  connect(Node2, Node3);
  connect(Node3, Node4);
  connect(Node4, Node5);
  connect(Node5, Node6);
  connect(Node6, Node3);
  ListNode* ret = EntranceNode(Node1);
  if (ret != nullptr)
  {
    cout << "链表的环入口节点为:" << ret->Data << endl;
  }
  else
  {
    cout << "传入指针为nullptr或者无环" << endl;
  }
  return 0;
}


本章完!

文章知识点与官方知

目录
相关文章
|
1月前
|
机器学习/深度学习 算法
24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交
1. **两两交换链表中的节点**:通过引入虚拟头结点,使所有节点都能采用统一的交换逻辑,避免对头结点单独处理。 2. **删除链表的倒数第N个节点**:利用双指针技巧,让快慢指针保持N个节点的距离,当快指针到达末尾时,慢指针正好指向待删除节点的前一个节点。 3. **链表相交**:先计算两链表长度并调整起点,确保从相同距离末尾的位置开始遍历,从而高效找到相交节点或确定无交点。 以上方法均在时间复杂度和空间复杂度上进行了优化,适合用于理解和掌握链表的基本操作及常见算法设计思路。
|
9月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
93 0
LeetCode第二十四题(两两交换链表中的节点)
|
9月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
94 0
Leetcode第十九题(删除链表的倒数第N个节点)
|
9月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
106 0
|
9月前
|
存储 算法 安全
HashMap常见面试题(超全面):实现原理、扩容机制、链表何时升级为红黑树、死循环
HashMap常见面试题:红黑树、散列表,HashMap实现原理、扩容机制,HashMap的jd1.7与jdk1.8有什么区别,寻址算法、链表何时升级为红黑树、死循环
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
108 2
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
142 1