环形链表| 8月更文挑战

131 阅读2分钟

前言

环形链表相关的问题,在链表中出现的也很多, 因此总结下环形链表相关的问题

  1. NC4 判断链表中是否有环(简单)
  2. NC3 链表中环的入口结点(中等)

1. 判断链表中是否有环

描述 : 判断给定的链表中是否有环。如果有环则返回true,否则返回false。

思路分析: 快慢指针, 慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,否则就说明无环

AC 代码:

    public boolean hasCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                return true;
            }
        }
        return false;
    }

2. 链表中环的入口结点

描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

思路分析:

  • 遍历链表 使用 Set 记录出现的节点, 当第一个重复节点出现时, 这个节点即为入环节点, 如果遍历完之后,都没有重复节点, 说明节点无环
  • 快慢指针, 当快慢指针相遇时, 让快指针移动到 head , 然后快慢指针 一起走, 再次相遇后,即为入环节点

image.png

A 为起始节点, B 是 入环节点, C 是第一次相遇的节点, D 是当慢指针到B 时 快指针的位置

第一次相遇的 慢指针走过 x + y

快指针 走过 2*(x + y) AB + BC + CD + DB + BC

x + y + CD +y + y = 2x + 2y

CD的长度 x - y 那么 BC 为x

所以当快慢指针相遇时, 让快指针移动到 head , 然后快慢指针 一起走, 再次相遇后,即为入环节点

AC 代码:

使用 Set 实现的版本, 时间复杂度 O(n) 空间复杂度 O(n)

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        Set<ListNode> set = new HashSet<>();
        while(pHead != null){
            if(set.contains(pHead)){
                return pHead;
            }
            set.add(pHead);
            pHead = pHead.next;
        }
        return null;
    }

快慢指针版本 时间复杂度 O(n) 空间复杂度 O(1)

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = pHead;
        ListNode fast = pHead;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(slow == fast){
                break;
            }
        }
        
        if(fast == null || fast.next == null){
            return null;
        }
        
        fast = pHead;
        
        while(fast != slow){
            slow = slow.next;
            fast = fast.next;
        }
        return fast;