LCP142 环形链表[leetcode-7]

LCP142 环形链表

先上结果

前排提醒,本文有两种解法,和原理分析
在这里插入图片描述

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

在这里插入图片描述

这道题真是让人思绪万千,有百般解法

  • 最笨的方法是,历遍,每过一个节点就存储起来,每到一个节点再对比。time:O(n*n) space:O(n)
  • 既然涉及对比,首先想到使用hash表来优化查找操作,hash的查找是O(1)所以time:O(n),space:O(n)
  • 最好的方法就是floyd寻圈算法,记录在经典算法这一节中.time:O(n),space:O(1)
    • 不需要额外的存储空间,只需要两个指针
hash的answer
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> visited;
        while (head != nullptr) {
            if (visited.count(head)) {
            //uset.count 此函数接受单个参数element 。表示容器中是否存在需要检查的元素。
                return head;
            }
            visited.insert(head);
            head = head->next;
        }
        return nullptr;
    }
};

floyd的算法

原理分析

  • 在起点处放置两个指针,一快一慢。快指针每次走两个,慢指针每次一个。

  • 循环该步骤,若无环,则到结尾也不会相遇。若存在一个环,那快慢指针将先后进入环中,而速度不同,必然追及,这是一个重要的结论:他们必然相遇在环上

  • 而且相遇的时候,循环的次数=慢指针走过的路程=环的长度,图示法如下
    -在这里插入图片描述

  • 好的,现在我们已经求得**是否有环?环多长?**的问题,下面让我们研究一下环的入口在哪里

  • 也很简单,把一个指针移到链表的开头,另一个指针保持在原地,然后让两个指针的速度都是1,最后两者必然相遇,相遇的点必然是环的开头,同理使用图解法

  • 相遇点到开头的长度=环的长度,既是AP=⚪P 今同减去路程BP,即为重置的指针路程相同,而速度一致,必然有同时到达环之开头B之事实
    在这里插入图片描述

  • 这就是精妙的Floyd判圈

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
       ListNode* fast=head, *slow=head;
       do{
        //如果fast或者下一个元素为null 则必为直线型
        if(!fast|| !fast->next) return nullptr;
        
        fast=fast->next->next;
        slow=slow->next;
       }while(fast!=slow);
        //相遇之后,必然存在节点
        fast=head;
        while(fast!=slow)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return fast;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值