解法一:迭代法
个人觉得迭代法是最直观易懂的,由于单链表的结构,至少要用三个指针才能完成迭代反转
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
// 迭代法
if head == nil || head.Next == nil{ // 空链表或者仅一个节点,无需反转
return head
}
cur := head
var nxt, pre *ListNode
for cur != nil{
nxt = cur.Next // 先记录下个节点位置
// 执行反转
cur.Next = pre
// 更新指针,处理下个节点
pre = cur
cur = nxt
}
// 最后cur会一直遍历到链表结尾之外nil,而pre即为尾结点,也就是反转后链表的起点
return pre
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
解法二:递归法
递归反转单链表的关键在于,这个问题本身是存在子问题结构的
例如,单链表 1->2->3->4,那么如果忽略这个头结点 1,只看 2->3->4 这个子链表,它也是个单链表对吧?那么,能不能先反转 2->3->4 这个子链表呢,然后再想办法把 1 接到反转后的 4->3->2 的最后面,是不是就完成了整个链表的反转?
reverseList(1->2->3->4) = reverseList(2->3->4) -> 1
reverseList 函数定义是这样的:输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点。
这就是「分解问题」的思路,通过递归函数的定义,把原问题分解成若干规模更小、结构相同的子问题,最后通过子问题的答案组装原问题的解。
最后的递归代码看起来非常简洁
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
if head == nil || head.Next == nil{
return head
}
last := reverseList(head.Next)
// 当链表递归反转之后,原本head.Next就会变为后半部分子链表的尾节点,那么它的next应该指向头节点
head.Next.Next = head
// 当链表递归反转之后,新的头结点是 last,而之前的 head 变成了最后一个节点,别忘了链表的末尾要指向 null
head.Next = nil
return last
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
反转链表 II
解法一:迭代法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseBetween(head *ListNode, left int, right int) *ListNode {
if head == nil || head.Next == nil{
return head
}
dummy := &ListNode{
Next: head,
}
// 找到第 left个节点的前驱节点
p0 := dummy
for i:=0; i<left-1; i++{
p0 = p0.Next
}
// 反转left到right这个区间
var pre *ListNode
cur := p0.Next // 第left个节点
for i := 1; i<=right-left+1; i++{
nxt := cur.Next
cur.Next = pre
pre = cur
cur = nxt
}
p0.Next.Next = cur
p0.Next = pre
return dummy.Next
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
解法二:抽象公共函数
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseBetween(head *ListNode, left int, right int) *ListNode {
if head == nil || head.Next == nil{
return head
}
if left == 1{ // 起点是头节点,反转前right个节点
return reverseN(head, right)
}
// 找到第 left个节点的前驱
pre := head
for i:=1; i<left-1; i++{
pre = pre.Next
}
// pre.Next即第 left个节点,以它为起点,反转前right-left+1个节点
pre.Next = reverseN(pre.Next, right-left+1)
return head
}
// 反转以head为起点的链表前n个节点
func reverseN(head *ListNode, n int) *ListNode{
if head == nil || head.Next == nil{
return head
}
cur := head
var pre,nxt *ListNode
for cur != nil{
nxt = cur.Next
// 执行反转
cur.Next = pre
// 更新指针
pre = cur
cur = nxt
n--
if n==0{
break
}
}
// 反转后pre是第n个节点(反转后的头节点),cur是第n+1个节点
head.Next = cur
return pre
}
另一种写法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseBetween(head *ListNode, left int, right int) *ListNode {
if head == nil || head.Next == nil{
return head
}
if left == 1{ // 起点是头节点,反转前right个节点
return reverseN(head, right)
}
// 找到第 left个节点的前驱
pre := head
for i:=1; i<left-1; i++{
pre = pre.Next
}
// pre.Next即第 left个节点,以它为起点,反转前right-left+1个节点
pre.Next = reverseN(pre.Next, right-left+1)
return head
}
// 反转以head为起点的链表前n个节点
func reverseN(head *ListNode, n int) *ListNode{
if head == nil || head.Next == nil{
return head
}
var pre *ListNode
cur, nxt := head, head.Next
for i:=0; i<n; i++{
cur.Next = pre
pre = cur
cur = nxt
if nxt != nil{
nxt = nxt.Next
}
}
// 反转后pre是第n个节点(反转后的头节点),cur是第n+1个节点
head.Next = cur
return pre
}