연결 목록에 링이 있는지 확인하고 링 항목을 찾습니다 (그림).

연결 목록에 링이 있는지 확인하고 링 항목을 찾는 알고리즘

@author : Jingdai
@date : 2020.12.26

제목 설명

주어진 연결 목록에 링이 있는지 확인하고, 링이 있으면 링의 항목을 찾아 출력하고, 링이 없으면 출력합니다 null.

아이디어와 코드

우선 첫 번째 질문은 연결 목록에 링이 있는지 여부를 판단하는 방법입니다. 빠르고 느린 포인터에 익숙한 아동용 부츠는 연결 목록에 링이 있는지 여부를 판단하는 것이 빠르고 느린 포인터로 해결할 수있는 일반적인 문제임을 알아야합니다.

우리는 두 개의 포인터, 하나의 느린 포인터 slowPointer와 하나의 빠른 포인터를 사용 fastPointer합니다. 모두 처음부터 시작하고 느린 포인터는 한 번에 한 걸음 씩, 빠른 포인터는 한 번에 두 걸음 씩 걷습니다. 링이 있으면 빠르기와 느린 포인터가 확실히 만나게됩니다.이를 기반으로 판단됩니다. 반지가 있는지 여부.

다음 질문은 반지의 입구를 찾는 방법입니다. 이 문제는 좀 더 복잡합니다. 아래 그림을보세요.

여기에 사진 설명 삽입

링의 바깥 쪽 길이는 l이고 빨간색 점이 만남의 지점입니다. 회의, 느린 포인터가 사라 때 l + a, 빠른 포인터가 사라 l + n (a + b) + a은, n회전 수, 그리고 빠른 포인터의 거리를 단순화하여 얻을 수 있습니다 느린 포인터의 두 배입니다 l = (n - 1) (a + b) + b. 제공되는 링 둘레 c를 얻을 수있다 l = (n - 1) c + b, 즉 l링과 회전 이내의 거리 n-1링 걸어 b동일한 거리. 이때 만남의 장소에서이 정도 먼 거리를 걸 으면 링 입구에 도착합니다. 그런 다음 처음부터 시작하도록 포인터를 설정하고 회의 지점에서 멀리 떨어진 다른 포인터를 시작할 수 있습니다. 만날 때, 사라진 경우 l, 링 진입 점에서 만날 것입니다. 이에 따라 링 입구를 찾을 수 있습니다.

참고 :주의 깊은 사람들은 왜 링의 느린 포인터 a가 원 안에 들어 가지 않는지 궁금해 할 수 있습니다 a. 느린 포인터는 한 원의 빠른 포인터 만 만나기 때문입니다. 느린 포인터가 링에 들어갈 때 빠른 포인터와 느린 포인터 사이의 거리는 링의 둘레보다 작아야합니다. 여기서는 빠른 포인터와 느린 포인터 사이의 거리가 링의 둘레와 같다고 가정하여 제한을받습니다. (실제로 사용할 수 없음). 그러면 빠른 포인터와 느린 포인터가 링 입구에 있습니다. 슬로우 포인터가 한 원으로 가고 빠른 포인터가 두 개의 원으로 가면 링 입구에서 다시 만나게됩니다. 느린 포인터는 한 원만 이동하고 거리는 가장 큽니다. 값을 사용할 수 없으므로 느린 포인터는 한 원으로 이동하지 않으므로 느린 포인터는 한 원 내에서 빠른 포인터를 확실히 만나게됩니다.

최종 코드는 다음과 같습니다.

public ListNode detectCycle(ListNode head) {
    
    

    if (head == null || head.next == null) {
    
    
        return null;
    }

    ListNode dummy = new ListNode();
    dummy.next = head;

    ListNode fastPointer = head.next;
    ListNode slowPointer = head;
    while (fastPointer != null && fastPointer.next != null) {
    
    
        slowPointer = slowPointer.next;
        fastPointer = fastPointer.next.next;
        if (fastPointer == slowPointer) {
    
     // hasCicle
            slowPointer = dummy;
            while (slowPointer != fastPointer) {
    
    
                slowPointer = slowPointer.next;
                fastPointer = fastPointer.next;
            }
            return slowPointer;
        }
    }
    return null;
}

추천

출처blog.csdn.net/qq_41512783/article/details/111754088