力扣141. 环形链表

134 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

力扣141. 环形链表

一、题目描述:

给你一个链表的头节点 head ,判断链表中是否有环。

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

img

输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 示例 2:

img

输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。 示例 3:

img

输入:head = [1], pos = -1 输出:false 解释:链表中没有环。

提示:

链表中节点的数目范围是 [0, 104] -10^5 <= Node.val <= 10^5 pos 为 -1 或者链表中的一个 有效索引 。

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/li… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、思路分析:

  1. 这道题考察了什么思想?你的思路是什么?

    这道题目如果用哈希表还是比较容易的,只要是有环,就一定会获取到重复的值。但是空间复杂度有点高。题目中进阶要求是用 O(1)(即,常量)内存解决此问题。所以我们需要用到Floyd 判圈算法,就是跑得快的在前面,而跑得慢的起点在后面,如果跑得慢的还能和跑得快的相遇,那么肯定是有圈了!

  2. 做题的时候是不是一次通过的,遇到了什么问题,需要注意什么细节?

    不是一次通过的,刚开始写的时候忘记了写head = head.next; 🍵。

  3. 有几种解法,哪种解法时间复杂度最低,哪种解法空间复杂度最低,最优解法是什么?其他人的题解是什么,谁的效率更好一些?用不同语言实现的话,哪个语言速度最快?

    看别人的题解看到了一种比较好的方法——Floyd 判圈算法,即龟兔赛跑算法。

    image-20220324095239967

    image-20220324095331639

    这个算法我在实现的时候,刚开始未考虑head或head->next为空的情况,导致出错。

三、AC 代码:

 /**
  * Definition for singly-linked list.
  * class ListNode {
  *     int val;
  *     ListNode next;
  *     ListNode(int x) {
  *         val = x;
  *         next = null;
  *     }
  * }
  */
 public class Solution {
     public boolean hasCycle(ListNode head) {
         Set<ListNode> set = new HashSet<ListNode>();
         while(head != null){
             if(set.add(head) == false){
                 return true;
             }
             head = head.next;
         }
         return false;
     }
 }

image-20220324103711100

image-20220324103719374

 /**
  * Definition for singly-linked list.
  * struct ListNode {
  *     int val;
  *     struct ListNode *next;
  * };
  */
 bool hasCycle(struct ListNode *head) {
     if(head == NULL || head->next == NULL) return false;
     struct ListNode *slow = head;
     struct ListNode *fast = head->next;
     while(slow!=fast){
         if(fast==NULL || fast->next==NULL){
             return false;
         }
         slow = slow->next;
         fast = fast->next->next;
     }
     return true;
 }

image-20220324103638437

image-20220324103648889

四、总结:

Floyd 判圈算法得好好了解,以后遇到需要判圈的问题可以用这个方法。