每日一题:链表中环的入口结点

文章目录

判断链表环的入口节点

描述

给定一个链表,判断该链表是否存在环。如果存在环,返回环的入口节点;如果不存在环,返回NULL

数据范围:

  • 链表长度 n n n: 0 ≤ n ≤ 10000 0 \leq n \leq 10000 0≤n≤10000
  • 链表中任意节点的值满足 ∣ v a l ∣ ≤ 100000 |val| \leq 100000 ∣val∣≤100000

复杂度要求:

  • 空间复杂度: O ( 1 ) O(1) O(1)
  • 时间复杂度: O ( n ) O(n) O(n)

输入

  • 输入一个链表的头节点 pHead,该链表可能包含环。

输出

  • 如果链表存在环,返回环的入口节点;否则返回 NULL

示例

示例 1:

输入:

复制代码
{3, 2, 0, -4}, 1

返回值:

复制代码
2

说明:

  • 链表{3, 2, 0, -4}有一个环,环的入口节点是值为2的节点。

示例 2:

输入:

复制代码
{1}, -1

返回值:

复制代码
NULL

说明:

  • 链表{1}没有环,返回NULL

示例 3:

输入:

复制代码
{-1, -7, 7, -4, 19, 6, -9, -5, -2, -5}, 6

返回值:

复制代码
6

说明:

  • 链表有环,环的入口节点是值为6的节点。

代码实现

c 复制代码
/**
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

/**
 * 找到链表中环的入口节点
 * 
 * @param pHead ListNode类 链表头结点
 * @return ListNode类 如果链表有环,返回环的入口节点,否则返回NULL
 */
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead) {
    // 判断链表是否为空或只有一个节点,若是则不存在环
    if (pHead == NULL || pHead->next == NULL) 
        return NULL;

    struct ListNode* fast = pHead->next->next;  // 快指针初始为第二个节点
    struct ListNode* slow = pHead->next;        // 慢指针初始为第一个节点

    // 快慢指针相遇判断是否有环
    while (fast != slow) {
        // 如果快指针到达链表末尾,则没有环
        if (fast == NULL || fast->next == NULL)
            return NULL;
        
        fast = fast->next->next;  // 快指针每次移动两步
        slow = slow->next;        // 慢指针每次移动一步
    }

    // 如果有环,重新初始化慢指针到链表头,从而找到环的入口
    slow = pHead;
    while (fast != slow) {
        fast = fast->next;  // 快指针每次移动一步
        slow = slow->next;  // 慢指针每次移动一步
    }

    // 快慢指针相遇时即为环的入口节点
    return slow;
}

思路解析

  1. 快慢指针法判断是否有环

    • 初始化两个指针 fastslow,其中 fast 指针每次移动两步,slow 指针每次移动一步。
    • 如果链表存在环,快慢指针最终会在环内某个节点相遇;如果链表没有环,快指针会到达链表的尾部(即 fast == NULLfast->next == NULL)。
  2. 找到环的入口节点

    • 当快慢指针相遇时,慢指针重新回到链表头节点,快指针保持在相遇节点处。
    • 然后,两个指针都每次移动一步,最终会在环的入口节点相遇。
  3. 时间复杂度

    • 快慢指针第一次相遇的时间复杂度为 O ( n ) O(n) O(n),找到环的入口节点的时间复杂度也是 O ( n ) O(n) O(n),所以总时间复杂度为 O ( n ) O(n) O(n)。
  4. 空间复杂度

    • 由于只使用了常数空间,因此空间复杂度为 O ( 1 ) O(1) O(1)。

注意事项:

  • 需要确保链表为空或只有一个节点时,返回 NULL
  • 快指针每次移动两步,慢指针每次移动一步,可以有效地判断环并找到环的入口。
相关推荐
刘马想放假3 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠4 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦11 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠12 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾12 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82112 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q12 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒12 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
疯狂成瘾者12 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
WL学习笔记12 天前
单项不带头不循环链表
数据结构·链表