数据结构 【带环链表2】

说到带环链表,有一道题目是这样说的,如果一个链表存在环,那么就返回进入环的第一个节点,如果链表没有环,那么就返回空。这里给出两种解题思路:

第一种解法:小结论解法

分析:这道题目可以拆分成两个部分,第一:检查链表是否带环。第二:返回带环链表的第一个进环节点。对于第一个部分,可以使用快慢指针的方式进行检测,这里再理一下思路:

· 关于第二点,这里先给出一个结论:假设存在两个指针meet和start,meet从fast和slow相遇的位置出发,start从链表的起点出发,那么meet和start一定会在链表刚进环的节点相遇。

这里给出证明过程:假设有一个带环链表如下图所示:

证明结果续:

所以算法的设计思路为:当meet和start从相应的条件开始移动时,它们相遇的节点就是链表环的入口节点。代码实现如下:

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast,*slow;
    fast = slow = head;
    while(fast && fast->next)//检测是否带环
    {
        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow)//相遇说明有环
        {
            struct ListNode* meet = fast;
            struct ListNode* start = head;

            while(meet != start)//循环停止即为入口节点
            {
                meet = meet->next;
                start =start->next;
            }
            return meet;
        }
    }
    return NULL;
}

第二种解法:转换法(将环断开,转换成求链表的第一个交点问题)

随即问题得到转化,可以先计算headA和headB的长度,计算出长度之前的差值,让长的链表先走差值步,然后两个链表同时往后走,在第一次节点地址相同的位置时,就是两个链表的第一个交点。代码实现如下:

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast,*slow;
    fast = slow = head;

    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;

        if(slow == fast)
        {
            struct ListNode* headB = fast->next;
            fast->next = NULL;

            struct ListNode* tailA = head,*tailB = headB;
            int lenA = 1,lenB = 1;

            while(tailA->next)
            {
                tailA = tailA->next;
                lenA++;
            }

            while(tailB->next)
            {
                tailB = tailB->next;
                lenB++;
            }
            int gap = abs(lenA-lenB);
            struct ListNode* longNode = head,*shortNode = headB;
            if(lenA < lenB)
            {
                longNode = headB;
                shortNode = head;
            }

            while(gap--)
            {
                longNode = longNode->next;
            }

            while(longNode != shortNode)
            {
                longNode = longNode->next;
                shortNode = shortNode->next;
            }

            return longNode;

        }
    }
    return NULL;
}
相关推荐
Darling噜啦啦5 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠6 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾6 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres8216 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q6 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒6 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
疯狂成瘾者6 天前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
WL学习笔记6 天前
单项不带头不循环链表
数据结构·链表
小糯米6016 天前
JS 数组
数据结构·算法·排序算法
小欣加油6 天前
leetcode3612 用特殊操作处理字符串I
数据结构·c++·算法·leetcode·职场和发展