关于反转链表系列,可以参考笔者之前写过的一篇博客
解法一:迭代法
解法二:递归
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseKGroup(head *ListNode, k int) *ListNode {
if head == nil {
return nil
}
// 区间 [start, end) 包含 k 个待反转元素
start, end := head, head
for i := 0; i < k; i++ {
// 不足 k 个,不需要反转,base case
if end == nil {
return head
}
end = end.Next
}
// 反转这 k 个元素
newHead := reverse(start, end)
// 递归反转后续链表并连接起来
start.Next = reverseKGroup(end, k)
return newHead
}
// 反转链表区间[start, end) 的节点,注意是左闭右开
func reverse(start, end *ListNode) *ListNode {
pre := &ListNode{Val: -1, Next:start}
cur := start
// 对比反转整个链表,while循环终止的条件改一下就行了
for cur != end {
nxt := cur.Next
// 翻转当前两节点
cur.Next = pre
// 前进,处理后续节点
pre = cur
cur = nxt
}
// 返回反转后的头结点
return pre
}
- 时间复杂度:O(n*k)≈O(N),总共有 N 个节点,每次处理反转 K 个节点的时间为 O (K),每个节点最多被访问两次(一次是在检查是否需要反转即是否足够k个时,另一次是在实际反转时)
- 空间复杂度:O(n/k),递归栈的调用深度是链表长度/每次处理k个节点,总共递归n/k次