# 链表翻转
https://github.com/Twelveeee/AlgorithmCamp2023/tree/main/02_reverselist
# 基本结构
# 链表构建
type LinkList struct { | |
Val interface{} | |
Next *LinkList | |
} | |
// 打印链表 | |
func (linkList *LinkList) PrintList() { | |
if linkList == nil { | |
return | |
} | |
fmt.Println(linkList.Val) | |
linkList.Next.PrintList() | |
} | |
// 新建链表 | |
func InitLinkList(val interface{}) *LinkList { | |
return &LinkList{ | |
val, nil, | |
} | |
} |
# 建立虚拟头结点辅助反转
// 建立虚拟头节点辅助翻转 | |
func reverseListV1(head *LinkNode) *LinkNode { | |
curr := head | |
newList, temp := &LinkNode{}, &LinkNode{} | |
for curr != nil { | |
temp = curr.Next | |
curr.Next = newList.Next | |
newList.Next = curr | |
curr = temp | |
} | |
return newList.Next | |
} |
# 直接操作链表实现反转
// 直接操作链表实现翻转 | |
func reverseListV2(head *LinkNode) *LinkNode { | |
curr := head | |
temp := &LinkNode{} | |
var pre *LinkNode | |
for curr != nil { | |
temp = curr.Next | |
curr.Next = pre | |
pre = curr | |
curr = temp | |
} | |
return pre | |
} |
# 递归翻转
// 递归 | |
func reverseListV3(head *LinkNode) *LinkNode { | |
if head.Next == nil || head == nil { | |
return head | |
} | |
newHead := reverseListV3(head.Next) | |
// 将当前节点的下一个节点的 Next 指针指向当前节点,实现翻转 | |
head.Next.Next = head | |
head.Next = nil | |
return newHead | |
} |
# 算法题
# 1. 指定区间反转
https://leetcode.cn/problems/reverse-linked-list-ii/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/02_reverselist/level_2/topic_1.go
给你单链表的头指针
head
和两个整数left
和right
,其中left <= right
。请你反转从位置left
到位置right
的链表节点,返回 反转后的链表 。解法: 建立虚拟头节点,走
left
步,再对right-left
步进行翻转,保证pre
节点一直指向翻转链表的头节点
func reverseBetween(head *ListNode, left int, right int) *ListNode { | |
left = left - 1 | |
right = right - 1 | |
dummyHead := &ListNode{} | |
dummyHead.Next = head | |
pre := dummyHead | |
for i := 0; i < left; i++ { | |
pre = pre.Next | |
} | |
curr := pre.Next | |
temp := &ListNode{} | |
for i := 0; i < right-left; i++ { | |
temp = curr.Next | |
curr.Next = temp.Next | |
temp.Next = pre.Next | |
pre.Next = temp | |
} | |
return dummyHead.Next | |
} |
# 2. 两两交换链表中的节点
https://leetcode.cn/problems/swap-nodes-in-pairs/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/02_reverselist/level_2/topic_2.go
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
解法:画个图一下走两步
func swapPairs(head *ListNode) *ListNode { | |
dummyHead := &ListNode{} | |
dummyHead.Next = head | |
pre, curr, next := dummyHead, dummyHead.Next, &ListNode{} | |
for curr != nil && curr.Next != nil { | |
next = curr.Next | |
curr.Next = curr.Next.Next | |
pre.Next = next | |
next.Next = curr | |
pre = pre.Next.Next | |
curr = pre.Next | |
} | |
return dummyHead.Next | |
} |
# 3. 链表加法
https://leetcode.cn/problems/add-two-numbers-ii/description/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/02_reverselist/level_2/topic_4.go
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
解法:可以用翻转链表,但是用两个栈会快点
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { | |
list1 := make([]int, 0, 100) | |
list2 := make([]int, 0, 100) | |
for l1 != nil { | |
list1 = append(list1, l1.Val) | |
l1 = l1.Next | |
} | |
for l2 != nil { | |
list2 = append(list2, l2.Val) | |
l2 = l2.Next | |
} | |
ans := &ListNode{} | |
index1, index2 := len(list1)-1, len(list2)-1 | |
carry := 0 | |
for index1 >= 0 || index2 >= 0 || carry != 0 { | |
temp := 0 | |
if carry != 0 { | |
temp += carry | |
carry = 0 | |
} | |
if index1 >= 0 { | |
temp += list1[index1] | |
index1-- | |
} | |
if index2 >= 0 { | |
temp += list2[index2] | |
index2-- | |
} | |
if temp >= 10 { | |
carry, temp = temp/10, temp%10 | |
} | |
ans.Next = &ListNode{temp, ans.Next} | |
} | |
return ans.Next | |
} |
# 4.K 个一组翻转链表
https://leetcode.cn/problems/reverse-nodes-in-k-group/
https://github.com/Twelveeee/AlgorithmCamp2023/blob/main/02_reverselist/level_3/topic_1.go
给你链表的头节点
head
,每k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k
的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
解法:先 check 能不能进行反转,然后进行翻转
func reverseKGroup(head *ListNode, k int) *ListNode { | |
dummpHead, tempNext := &ListNode{}, &ListNode{} | |
dummpHead.Next = head | |
pre := dummpHead | |
curr := pre.Next | |
for curr != nil { | |
// check | |
tail := curr | |
for i := 0; i < k; i++ { | |
if tail == nil { | |
return dummpHead.Next | |
} | |
tail = tail.Next | |
} | |
// do reverse | |
for i := 0; i < k-1; i++ { | |
tempNext = curr.Next | |
curr.Next = tempNext.Next | |
tempNext.Next = pre.Next | |
pre.Next = tempNext | |
} | |
pre = curr | |
curr = curr.Next | |
} | |
return dummpHead.Next | |
} |