算法:Linked List Cycle(环形链表)

说明

算法:Linked List Cycle
LeetCode地址:https://leetcode.com/problems/linked-list-cycle/

题目:
Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.


Example 2:

Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.


Example 3:

Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.


Follow up:

Can you solve it using O(1) (i.e. constant) memory?

解题思路1

环形链表只要判断是否经过相同的对象,用到去重容器Set来存储已经遍历的数据,遍历链表,判断是否存在于Set中。因为需要Set容器,空间复杂度为O(n), 时间复杂度为O(n).

代码实现1

import java.util.HashSet;
import java.util.Set;

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class LinkedListCycle {
    public boolean hasCycle(ListNode head) {
        Set<Integer> pastSet = new HashSet<>();
        while (head != null) {
            if (pastSet.contains(head.val)) {
                return true;
            } else {
                pastSet.add(head.val);
                head = head.next;
            }
        }

        return false;
    }
}

代码执行效率1

Runtime: 6 ms, faster than 11.95% of Java online submissions for Linked List Cycle.
Memory Usage: 35.4 MB, less than 99.35% of Java online submissions for Linked List Cycle.

解题思路2

题目要求是内存复杂度在O(1), 也就是不能用Set容器。需要用指针的方法处理:
用两个步长分别为slowStep = 1,和fastStep = 2的指针,如果能遍历到下个结点是null,说明不是循环列表. 循环列表里面,两个步长的相差为1,肯定会相遇。

证明:异常情况:两个步长不相遇的情况,只有一种可能,步长1在步长2的节点前面相差1. 循环区间的长度为K,那么K有两种情况,要么是奇数,要么是偶数。

先假设遍历的位置,slowIndex = 1, fastIndex = 0;(实际上slowIndex = 2, fastIndex = 1也是相同的证明方法)

  1. K == 奇数:fastStep到终点,slowIndex = 1 + ½ * (k - 1) , fastIndex = k - 2; 再走步数 ½ * (k - 1) , slowIndex = k, 也就是 slowIndex = 0, fastIndex = k - 1; 下一步 slowIndex == fastIndex == 1.

  2. K == 偶数:fastStep到终点,slowIndex = 1 + ½ * k , fastIndex = k - 1; 再走步数½ * k,slowIndex = 1 + k, 相当于 slowIndex = 1 , fastIndex = k, 相当于 fastIndex = 0; 下一步 slowIndex == fastIndex == 1.

空间复杂度为O(1); 时间复杂度为 O(n) , 因为循环区间次数假设为k,实为O(n+k).

代码实现2

public class LinkedListCycle {
    public boolean hasCycleWithTwoPoint(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slowNode = head;
        ListNode fastNode = head.next;
        while (slowNode != fastNode) {
            if (slowNode == null || fastNode == null || fastNode.next == null) {
                return false;
            }
            slowNode = slowNode.next;
            fastNode = fastNode.next.next;
        }

        return true;
    }
}

代码执行效率2

Runtime: 0 ms, faster than 100.00% of Java online submissions for Linked List Cycle.
Memory Usage: 39.6 MB, less than 5.15% of Java online submissions for Linked List Cycle.

总结

考查循环链表,和空间复杂度的优化。

代码下载:
https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/popular/LinkedListCycle.java

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/87890399
今日推荐