【剑指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
如何递归反转链表
- 明确递归函数的输入输出
输入:
输出: 返回的newHead都是原来的尾节点。
- 记忆输入到输出的调整过程:
2.1 头节点接上反转链表
2.2 头节点next指针置空
- 返回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
}