[Leetcode] 141. 环形链表

题目

leetcode 141. 环形链表

在这里插入图片描述
在这里插入图片描述

题解

leetcode给出的方法参数只有ListNode,一开始我一直搞不懂这个pos要怎么接收??

思路一:使用哈希表,让每一个节点做key,value记录每一个节点出现的次数。如果有一个节点出现两次说明有环。

这里使用HashMap或者HasnSet都可以。

    /**
     * 每次把哈希表中没有的结点添加到哈希表中。
     * 如果是环,那么在尾结点的下一个结点肯定在哈希表中,此时就可以说明有环。
     * 如果不是环,那么在尾结点的下一个结点就是null,此时结束循环,说明不是环
     * @param head
     * @return
     */
    public boolean hasCycle(ListNode head) {
    
    
        Set<ListNode> set = new HashSet<>();
        while(head != null) {
    
    
            if(set.contains(head)) {
    
    
                // 说明存在环
                return true;
            } else {
    
    
                set.add(head);
            }

            head = head.next;
        }
        return false;
    }

复杂度:

  • 时间复杂度:遍历N次,所以为O(N)。
  • 空间复杂度:使用一个哈希表,最多存储N个节点,所以为O(N)。

思路二:使用双指针,一个是慢指针slow,每次移动一个节点,另一个是快指针fast,每次移动两个节点。

对于快慢指针,需要解决一个问题,比如一个单链表如果从左到右使用快慢指针遍历,必定是快指针先遇到null。那么是不是:fast.next.next == null ?其实没有必要,只需要:fast.next == null 就行。但是仅仅这样是错误的,快慢指针还得考虑节点个数的奇偶问题。对于奇数来说这样没问题,但是对于偶数就有问题了,会出现空指针异常,可以画画图,快指针最后会跳到null去,你可能会说,跳到null去不正好结束吗?是,不过在还得进行一轮的判断是否结束才算结束,问题就是出现在这最后一次判断这,空指针调用了next。所以还得判断:fast == null。

总结(掌握):对于快慢指针,需要解决节点个数的奇偶问题,因为快指针最先到达结尾,所以快指针需要两个条件来判断是否结束:如果当前快指针为空或者快指针的下一个节点为空,表示结束

  • 假设是无环的情况下,那么就是遇到null,必定是快指针先遇到。
  • 假设是有环的情况下,那么就是不会遇到null,但是快慢指针就一直循环下去吗?看下图:

在这里插入图片描述

通过上图,发现如果链表是环,那么快慢指针一直循环就一定能相遇。(我不会证明。。)

代码:

    /**
     * 
     * @param head
     * @return
     */
    public boolean hasCycle2(ListNode head) {
    
    
        ListNode fast = head;
        ListNode slow = head;
        // 如果不是环,结点个数影响快指针跳的位置,所以需要写一个处理奇偶情况。此题跟求链表的中间结点那道的条件一样。不过不需要去考虑中间结点有2个的问题
        while(fast != null && fast.next != null) {
    
    
            // 必须先走,才判断是否为环
            // 慢指针走一步
            slow = slow.next;
            // 快指针走两步
            fast = fast.next.next;
            // 如果遇到环,则快指针和慢指针一定会在环相遇
            if(fast == slow) {
    
    
                return true;
            }
        }
        return false;
    }

因为这道题比较特殊,还可以这样:

    public boolean hasCycle(ListNode head) {
    
    
        if(head == null || head.next == null) {
    
    
            return false;
        }
        // 两种写法
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast != slow) {
    
     
            if(fast == null || fast.next.next == null) {
    
    
                return false;
            }
            fast = fast.next.next;
            slow = slow.next;
        }

        return true;
    }

复杂度:

  • 时间复杂度:O(N)
  • 空间复杂度:就用两个指针,可以当作O(1)

猜你喜欢

转载自blog.csdn.net/weixin_41800884/article/details/107775494