【剑指offer】24.反转链表 && 92. 反转链表 II

速记: 三指针逐个反转 or 递归

题意理解

      1->2->3->null

null<-1<-2<-3

三指针逐个反转

Q: 如何分析出需要3个指针
A:
cur用于遍历链表(表示当前需要反转的节点)。
pre,next是保存当前节点的前后节点, 防止链表断掉。

next的由来: cur一反转,则后续链表丢失。(nil<-1...2->3-nil)
pre的由来: cur需要指向前一个节点,而从cur本身是不能直到前一个节点的,所以要用pre来保存前一个节点: 比如此时2不知道前一个节点是1 (nil<-1 2(cur)->3(next)->nil)

Q: 迭代继续或终止条件
A: 直到curl==null则退出循环, 也就是cur!=nil则继续循环

Q: 主体步骤
A: // save next // reverse // move on

如何递归反转链表

  1. 明确递归函数的输入输出
    输入:

输出: 返回的newHead都是原来的尾节点。

  1. 记忆输入到输出的调整过程:
    2.1 头节点接上反转链表

2.2 头节点next指针置空

  1. 返回newHead

92. 反转链表 II

func reverseBetween(head *ListNode, m int, n int) *ListNode {
    // 1 + reverse(2-4) +5
    var preStart,start,end,endNext *ListNode
    // 如果m==1,则说明头节点也要反转,因为头节点没有pre节点,所以增加dummy作为其pre节点. 如 1->2 (m=1,n=2) => (1<-2) // 增加dummy统一为中间节点来处理
    dummy := &ListNode{Next:head} 
    cur := dummy
    count := 0
    for cur != nil {
        count++
        if count == m {
            preStart = cur
            start = cur.Next
        }
        if count == n+1 {
            end = cur
            endNext = end.Next
        }
        cur = cur.Next
    }
    // input 2->3->4(end)
    // output 1-> 2<-3<-4 5
    // adjustto 1-> 4->3->2->nil ->5
    subHead := reverse(start,end) 
    preStart.Next = subHead
    start.Next = endNext
    return dummy.Next
}

// input 2->3->4(end) ->5 // 子问题输入 2->reverse(3->4) // 子问题的解 2->(nil<-3<-4) // 构造为父问题的解 nil<-2<-3<-4
// output 1-> nil<-2<-3<-4 5
func reverse(start,end *ListNode) *ListNode{
    if start == end {
        return start
    }
    newHead := reverse(start.Next,end)
    start.Next.Next = start // 2<-3
    start.Next = nil
    return newHead
}
原文地址:https://www.cnblogs.com/yudidi/p/12551681.html