Java面试系列-算法-判断链表是否有环并找出环的入口

165 阅读1分钟

题目

找出链表中环的入口节点

给定一个单链表,如果有环,返回环的入口结点,否则,返回null

准备


import java.util.HashSet;

class LishNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }
}

步骤

方法

Hash

  • 遍历链表
  • 将节点add到HashSet中
  • 判断当前节点的next是否存在于HashSet中如果存在则证明有环。
  • 环入口为当前存在于HashSet中的节点
public ListNode hasCycle4HashNode(ListNode head) {
    HashSet<ListNode> hashSet = new HashSet<>();
    while (head != null) {
        if (hashSet.contains(head)) {
            return head;
        } else {
            hashSet.add(head);
            head = head.next;
        }
    }
    return null;
}

快慢指针

  • 声明快指针和慢指针均为head
  • 循环链表配速为慢指针为一步,快指针为2步
  • 如果有环的话,快指针肯定会和慢指针相遇
  • 相遇之后快慢指针分别走的距离为
    • 快:ABCBC
    • 慢:ABC image.png

快指针速度为慢指针的二倍所以等量关系计算为:设AB为X,BC为Y 2(X+Y) = X + Y + Y + CB CB = X

所以两指针相遇后,慢指针从C出发,快指针从A出发两者再相遇时的节点则为环入口节点。

public ListNode entryListCycle(ListNode head) {
    if (head == null) return null;
    ListNode fast = head;
    ListNode slow = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        //快慢指针相遇的节点
        if (fast == slow) {
            break;
        }
    }
    
    // 若是快指针指向null,则不存在环
    if(fast == null || fast.next == null) return null;

    fast = head;
    while(fast != slow) {
        fast = fast.next;
        slow = slow.next;
    }
    return slow;
}

参考

blog.nowcoder.net/n/b117b5636…