解法一:反转链表
参考旋转数组这一题的解法,对于链表,向右轮转k个元素,其实就是分别把包含前 len-k个元素和后 k个元素的两个子链表交换位置,子链表内部元素要保持原来的顺序不变,具体分为三步:
- 反转整个链表
- 反转前k个节点
- 反转后len-k个节点
反转链表系列可以参考这篇题解
具体解法中,可能还涉及一些边界情况的特殊判断,例如:
- 链表为空,无需旋转
- 链表只有一个节点,无需旋转
- k=0,那就是不旋转
- k为len的整数倍,那就是旋转了n圈后回到原样,相当于不旋转
- k > len,循环旋转的多圈可以略去,只需要考虑k%len的旋转次数
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil || head.Next == nil || k == 0{
return head
}
// 计算链表长度
listLen := 0
cur := head
for cur != nil{
listLen++
cur = cur.Next
}
// 边界情况判断
if k == listLen{
return head
}else if k > listLen{
k = k%listLen
if k == 0{
return head
}
}
// 迭代法反转整个链表
var pre, nxt *ListNode
cur = head
for cur != nil{
nxt = cur.Next
cur.Next = pre
pre = cur
cur = nxt
}
// 反转后链表的头节点为pre
revHead := pre
// 反转前k个节点
res := reverseBetween(revHead, 1, k)
// 反转后len-k个节点
res = reverseBetween(res, k+1, listLen)
return res
}
func reverseBetween(head *ListNode, left, 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, nxt *ListNode
cur := p0.Next // 第left个节点
for i := 0; i<right-left+1; i++{
nxt = cur.Next
cur.Next = pre
pre = cur
cur = nxt
}
// p0是反转区间的前驱节点,p0.Next指向反转区间的第一个节点
// cur此时走到了反转区间外的下一个节点
// pre是区间反转后的第一个节点
p0.Next.Next = cur
p0.Next = pre
return dummy.Next
}
解法二:闭合成环
旋转后新链表的最后一个节点为原链表的第len-k(准确来说是k%len)个节点,我们可以先将给定的链表连接成环,然后将指定位置断开
- 首先计算出链表的长度 n,并找到该链表的末尾节点,将其与头节点相连。这样就得到了闭合为环的链表
- 找到新链表的最后一个节点(即原链表的第len-k%len个节点),将当前闭合为环的链表断开,即可得结果
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil || head.Next == nil || k == 0{
return head
}
listLen := 1
cur := head
for cur.Next != nil{ // 遍历到最后一个节点
listLen++
cur = cur.Next
}
cur.Next = head // 尾节点指向头节点,连接成环
pos := listLen - k%listLen // 新链表的尾节点位置
// 即使k是 len的整数倍,这里计算得到pos为链表的最后一个节点,断开环后一样可以得到答案
for pos > 0{
cur = cur.Next
pos--
}
newHead := cur.Next
cur.Next = nil
return newHead
}