바이트 측면에서 면접관은 링크 목록을 마스터하는 데 능숙하지 않다고 말했습니다.

Python 전투 커뮤니티

자바 전투 커뮤니티

길게 눌러 아래 QR 코드를 확인하고 필요에 따라 추가 하세요.

고객 서비스를 추가하려면 QR 코드를 스캔하세요.

Python 커뮤니티 들어가기 ▲

고객 서비스를 추가하려면 QR 코드를 스캔하세요.

자바 커뮤니티 진입

작자 명 丨 P.yh

출처 丨 5 분 학습 알고리즘 (ID : CXYxiaowu)

안녕하세요, 저는 Wu 형제입니다. 오늘은 매우 기술적 인 알고리즘 질문을 공유하고 있습니다.이 질문은 연결 목록의 몇 가지 지식 포인트를 조사합니다. 지난 6 개월 동안 바이트 비트 인터뷰에서 수십 번이나있었습니다.

제목 설명

단일 연결 목록이 주어지면 L : L 0L 1 →… → L n-1L n , 다음과 같이
재 배열하십시오. L 0L nL 1L n-1L 2L n -2 →…

노드 내부의 값만 변경할 수는 없지만 실제로 노드를 교환해야합니다.

예 1 :

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

예 2 :

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

질문 출처 : https://leetcode-cn.com/problems/reorder-list/

문제 분석

주제는 많은 정보를 제공하지 않고 연결 목록을 입력 한 다음 특정 규칙에 따라 연결 목록 노드의 위치를 ​​변경할 수 있습니다. 변환 정보는 다음과 같습니다.

L0→L1→…→Ln-1→Ln
    变换为
L0→Ln→L1→Ln-1→L2→Ln-2→…

그리고 제목은 노드의 값을 변경할 수없는 것을 요구합니다.

이 질문은보다 복잡한 연결 목록 문제 범주에 속하며 일반적인 연결 목록 작업을 검토하고 프로그래밍의 기본 기술을 연습 할 수 있습니다.

제목을 얻을 때 가장 먼저 생각해야 할 것은 두 번째 형식으로 변환하는 방법입니다 .

비교 결과 연결 목록의 전반부가 후반부를 교차하는 것처럼 보이지만 후반부와 전반부가 서로 평행하지 않은 것으로 보입니다.

다시보세요, 아래 첨자의 앞쪽 절반은 증가하고, 아래 첨자의 두 번째 절반은 감소합니다.

이 시점에서 후반부가 반전 된 다음 전반과 교차하는 것을 알 수 있어야합니다.

기본적으로이 주제 의 아이디어는 이와 같습니다. 일반적으로 링크드리스트의 문제는 생각하기 어렵지 않고 특정 구현에서 어렵습니다. 정말 잘 모르겠다면 링크드리스트를 배열로 생각할 수 있습니다 .

이 문제를 해결하기위한 세 단계가 있으며,이 세 단계는 연결 목록의 조사로서 별도로 취할 수 있습니다.

첫 번째 단계는 찾을 목록의 중간 지점입니다. 여기서는이 기술을 사용해야합니다. 포인터 속도, 참고 사항, 주제의 요구 사항에 따라 포인터 속도의 시작 위치를 조정하고 싶습니다. 알 수 있습니다.

두 번째 단계는 일반적으로 정상 순환이 true 인 반전 된 목록 이며 세 개의 포인터가 교대로 완료되어야합니다.

세 번째 단계는 목록병합하는 것입니다 .이 단계는 이전 두 단계와 비교하여 조금 생각하기 어려울 것입니다.주의해야 할 점은 루프를 벗어난 상태에서 여전히 판단해야한다는 것입니다.

더 구체적으로 말하자면 코드 구현에 따라 다릅니다. 연결 목록과 관련된 주요 문제는 더 많은 연습이며 많은 작업이 없습니다 .

참조 애니메이션

참조 사진

참조 코드

public void reorderList(ListNode head) {
    if (head == null || head.next == null) {
        return;
    }

    // 步骤 1: 通过快慢指针找到链表中点
    // 通过调节快慢指针的起始位置,可以保证前半部分的长度大于等于后半部分
    ListNode slow = head, fast = head.next;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    // 步骤 2: 反转后半部分的链表
    // 在反转之前需要的一个操作是将前后半部分断开
    ListNode second = slow.next;
    slow.next = null;
    second = reverseList(second);

    // 步骤 3: 合并前半部分链表以及反转后的后半部分链表
    mergeList(head, second);
}

private ListNode reverseList(ListNode head) {
    ListNode prev = null, tmp = null, pointer = head;
    while (pointer != null) {
        tmp = pointer.next;
        pointer.next = prev;
        prev = pointer;
        pointer = tmp;
    }

    return prev;
}

private void mergeList(ListNode first, ListNode second) {
    ListNode dummy = new ListNode(0);
    ListNode pointer = dummy;

    while (first != null && second != null) {
        pointer.next = first;
        first = first.next;
        pointer.next.next = second;
        second = second.next;
        pointer = pointer.next.next;
    }

    // 因为我们之前找中点的时候保证了前半部分的长度不小于后半部分的长度
    // 因此交叉后,多出来的部分只可能是前半部分,判断前半部分即可
    if (first != null) {
        pointer.next = first;
    }
}

程序员专栏 扫码关注填加客服 长按识别下方二维码进群

최근 흥미 진진한 추천 콘텐츠 :  

 중국, 미국, 일본 및 인도의 프로그래머 소득 비교

 프로그래머에게 슬픈 하루

 시작부터 소스 코드까지 SringMVC, 이것으로 충분합니다.

 10 가지 Python 비주얼 애니메이션, 신중하고 아름답게


여기에서 좋은 기사를 보고 더 많은 사람들과 공유 하세요 ↓↓

추천

출처blog.csdn.net/Px01Ih8/article/details/109268608