[인터뷰 클래식] 리버스 링크리스트-링크리스트에서 바늘을 꿰는 방법

전체 연결 목록 반전 (단순)

매우 간단하고 고전적인 주제입니다. 즉, 1-> 2-> 3-> 4-> 5 에서 5-> 4-> 3-> 2-> 1반전 합니다.

두 가지 사고 방식, 반복재귀가 있습니다. 먼저 그림을 본 다음 코드를보십시오.

여기에 사진 설명 삽입

1) 반복-클래식 더블 / 3 포인터

class Solution {
    
    
    public ListNode reverseList(ListNode head) {
    
    
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
    
    
            ListNode nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}

2) 재귀-하위 문제가 해결되었다고 가정

class Solution {
    
    
    public ListNode reverseList(ListNode head) {
    
    
        if (head == null || head.next == null) {
    
    
            return head;
        }
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

 
 

전체 연결 목록 반전 (고급)

여기에 또 다른 사고 방식, 즉 지속적으로 "전면을 참조"하는 방법이 있습니다.

1) 어느 노드가 순회되고 어느 노드가 첫 번째 노드로 전진합니다.

2)이 프로세스에는 더미 가상 노드가 필요합니다.

3) 이동하는 이중 포인터는 cur 및 nxt입니다 (cur 중 다음 포인터는 매번 nxt입니다. nxt는 계속 진행하기 때문에 cur은 자동으로 뒤로 이동합니다.)

dummy -> 1 -> 2 -> 3 -> 4 -> 5		提前2
dummy -> 2 -> 1 -> 3 -> 4 -> 5		提前3
dummy -> 3 -> 2 -> 1 -> 4 -> 5		提前4
dummy -> 4 -> 3 -> 2 -> 1 -> 5		提前5
dummy -> 5 -> 4 -> 3 -> 2 -> 1		大功告成!
class Solution {
    
    
	public ListNode reverseList3(ListNode head) {
    
    
        if (head == null) {
    
    
            return null;
        }
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy;
        ListNode cur = head;
        ListNode nxt = null;
        while (cur.next != null) {
    
    
            nxt = cur.next;
            cur.next = nxt.next;
            nxt.next = pre.next;
            pre.next = nxt;
        }
        return dummy.next;
    }
}

 
 

연결 목록의 일부 반전 (난이도)

반복과 재귀를 배우는 것만으로도 충분하지만 왜 세 번째 "초기"방법을 배워야합니까? 이 질문에 대비하는 것입니다.

여기에 사진 설명 삽입

반복 / 재귀를 사용하는 경우 알고리즘과 구현 및 경계 처리가 매우 까다 롭습니다.

1) 왼쪽과 오른쪽의 위치와 센티넬의 위치를 ​​찾기 위해 한 번 횡단하십시오.

2) 연결 목록을 가로 채고, 반복 / 재귀를 사용하여 반전하고, 헤드 / 테일 포인터도 사용합니다.

3) 다시 스플 라이스;

세 번째 방법을 사용하면 한 번만 순회됩니다.

1) for (left)는 pre의 위치를 ​​찾아 수정합니다.

2) (오른쪽-왼쪽) 일부 노드에서 작업을 계속 진행하여 되돌릴 수 있습니다.

3) 끝;

여기에 사진 설명 삽입

class Solution {
    
    
    public ListNode reverseBetween(ListNode head, int left, int right) {
    
    
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode cur = null;
        ListNode nxt = null;
        for (int i = 0; i < left - 1; i++) {
    
    
            pre = pre.next;
        }
        cur = pre.next;
        for (int i = 0; i < right - left; i++) {
    
    
        	// 这段取“nxt然后提前”的代码,像是在链表上穿针引线 >_<
            nxt = cur.next;
            cur.next = nxt.next;
            nxt.next = pre.next;
            pre.next = nxt;
        }
        return dummy.next;
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

끝 끝 E N D

추천

출처blog.csdn.net/m0_46202073/article/details/114978040