美文网首页
链表的环相关问题

链表的环相关问题

作者: _空格键_ | 来源:发表于2020-05-07 16:57 被阅读0次

    题目

    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    说明: 不允许修改给定的链表。

    链表节点环图示

    解题

    方法 1:哈希表

    使用一个 Set /List保存已经访问过的节点,我们可以遍历整个列表,检查每一个节点是否已存在Set中,如果存在即可返回第一个出现重复的节点,否则不存在环返回null。

    1.1 算法

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            Set<ListNode> visited = new HashSet<ListNode>();
    
            ListNode node = head;
            while (node != null) {
                if (visited.contains(node)) {
                    return node;
                }
                visited.add(node);
                node = node.next;
            }
    
            return null;
        }
    }
    

    1.2 复杂度分析

    • 时间复杂度O(n)
    • 空间复杂度O(n)

    方法 2:Floyd 算法

    也称双指针/快慢指针法。就是用两个指针,从头开始遍历,一个指针步进+1,一个指针步进+2,如果链表存在环,这两个指针总会相遇。想象下环形操场,两个人同起点同方向跑步,一个快一个慢,他们总会在某一点相遇,同理。

    2.1 算法

    本算法分两步:第一步检查是否存在环,第二部如果存在环,找出环的入口。

    通过数学模型计算,第一次相遇后,快慢指针走过的距离 2S慢=S快,即

    2(F + a) = F + N(a + b) + a
    2F + 2a = F + 2a + b + (N - 1)(a + b)
              F = b + (N - 1)(a + b)

    • F是到达入口点长度
    • N为快指针跑过第几个整圈后会与慢指针相遇

    下图便于理解


    环算法模型
    public class Solution {
        private ListNode getIntersect(ListNode head) {
            ListNode tortoise = head;
            ListNode hare = head;
    
            // 如果存在环,一定会相遇;如果不存在环,hare最先到达null
            while (hare != null && hare.next != null) {
                tortoise = tortoise.next;
                hare = hare.next.next;
                if (tortoise == hare) {
                    return tortoise;
                }
            }
    
            return null;
        }
    
        public ListNode detectCycle(ListNode head) {
            if (head == null) {
                return null;
            }
    
            //寻找相遇点,如果存在环,返回相遇点;如果不存在,返回null
            ListNode intersect = getIntersect(head);
            if (intersect == null) {
                return null;
            }
    
            // 寻找入环点,需要两个指针+1速度,一个从头开始,一个从相遇点开始,两个指针相遇时即为环入口
            ListNode ptr1 = head;
            ListNode ptr2 = intersect;
            while (ptr1 != ptr2) {
                ptr1 = ptr1.next;
                ptr2 = ptr2.next;
            }
    
            return ptr1;
        }
    }
    

    2.2 复杂度分析

    • 时间复杂度O(n)
      如果存在环,遍历实现以慢指针次数为准;如果不存在环,遍历时间以快指针次数为准。
    • 空间复杂度O(1)
      只开销了几个指针变量

    [注]
    详细参考: LeetCode 142.环形链表 II

    相关文章

      网友评论

          本文标题:链表的环相关问题

          本文链接:https://www.haomeiwen.com/subject/nqioghtx.html