判断链表是否有环--三种思路

0x01.问题

给定一个链表,判断链表中是否有环。
注:这个环可以是尾节点连接到前面的任意一个节点

0x02.分析三种方法

第一种:哈希表

最容易想到的,就是每遇到一个节点,如果不存在,就把它存入哈希表,存在就直接返回true。没有一个重复的就返回false

注意:
  • 最好使用unordered_set,而不是set,更节省时间。
  • 存的数据类型一定要是指针,不能是值,因为值可能存在相同的。
优劣势分析:
  • 空间换取时间,只进行依次遍历,但多使用了一个链表的空间。
  • 时间复杂度为:O(N)
  • 空间复杂度为:O(N)

第二种:快慢双指针

这是一个常识,如果在一个环形跑道上赛跑,快的人和慢的人一定会相遇。所以我们可以使用一个快指针,每次走两步,一个慢指针,每次走一步,如果存在环,一定会相遇,如果快指针遇到空了,就说明没有环。

注意:
  • 初始化时快指针应该是head->next
优劣势分析:
  • 以时间换取空间,不过时间消耗的也不多,进环的时候,迭代次数会多一些。
  • 时间复杂度:O(N+K)K为环的长度。
  • 空间复杂度:O(1)。没有使用额外的空间。

附加:如果需要返回成环的那个节点,我们只需要找到快慢指针相遇的点,用指针p代替,然后再用一个指针指向头指针,用q代替,每次同时将它们挪动一步,直到它们相遇,它们相遇的点就是环的入口!这里省略数学证明,这其实也是Floyd算法的一种应用。

第三种:标志法

我们可以给每个访问过变量记上一个标记,如果下次仍然发现了这个标记,说明肯定成环。

常见的标价法是改变自身的值,通常为一个大数,表示一般不可能取到的值,当然,这种方法严格意义上说是不严谨的。

也可以把每个访问过的节点指向head节点,意义是强行改变指针,也可以改变指针为某一地址,总之,只要能让原先节点变得有标志意义。

注意:
  • 换值严格意义上是错误的,但通常可行,我们可以换成一个比较大的数。
  • 改变指针的思想是完全可用的。
优劣势分析:
  • 这种方法的最大弊端就是改变了原来的链表结构,意义不大,一般只在仅仅为了判断是否成环的时候使用,否则链表结构改变是不可逆的,这个链表将无法使用。
  • 时间复杂度:O(N)
  • O(1)

0x03.解决代码–哈希表

bool hasCycle(ListNode *head) {
   unordered_set<ListNode*> map;
   while(head){
       if(map.count(head)) return true;
       else map.insert(head);
       head=head->next;
   }
   return false;
 }
 

0x04.解决代码–快慢双指针

bool hasCycle(ListNode *head) {
    if(!head||!head->next) return false;
    ListNode*slow=head;
    ListNode*fast=head->next;
    while(slow!=fast){
        if(!fast||!fast->next) return false;
        slow=slow->next;
        fast=fast->next->next;
    }
    return true;
}

0x05.解决代码–标志法

bool hasCycle(ListNode *head) {
   int flag=1e6;
   while(head){
       if(head->val==flag) return true;
       else head->val=flag;
       head=head->next;
   }
   return false;
}

ATFWUS --Writing By 2020–03–24

  • 24
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值