题目:旋转链表
思路分析
- 向右旋转k位,意味着倒数第k位指到链表首位,即1->2->3->4->5 旋转2位,就是倒数第二位4,旋转之后4->5->1->2->3。这里可以看成两段链表的拼接:4->5 拼接 1->2->3
- 找到链表1:4->5 和链表2:1->2->3
- 注意1:将5指向1的时候,需要先将3->4这个指向断开,变成3->nil,否则一旦5指向1了就变成环形链表,会报错。
- 注意2:k 可能会大于链表长度,所以这里需要找的偏移量实际是 k%链表长度,当偏移量为0时旋转后不变,直接返回原链表即可。
复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)
-
时间复杂度: O ( n ) O(n) O(n)
rotateRight 函数中包含两个主要循环,第一个循环用于计算链表的长度,需要遍历整个链表,时间复杂度为 O ( n ) O(n) O(n),其中 n 是链表的长度。第二个循环用于找到倒数第 k 个节点的位置,同样需要遍历链表,时间复杂度为 O ( n ) O(n) O(n)。因此,总的时间复杂度为 O ( n ) O(n) O(n)。
-
空间复杂度: O ( 1 ) O(1) O(1)
该函数只使用了常量级别的额外空间,主要用于存储几个指针变量和常量。因此,空间复杂度为 O ( 1 ) O(1) O(1)。没有使用与输入规模成正比例的额外数据结构。
Go代码
type ListNode struct {
Val int
Next *ListNode
}
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil || head.Next == nil || k == 0 {
return head
}
// 找到正数k后1位的位置
slow, fast, tmp := head, head, head
len := 0
for tmp != nil {
len++
tmp = tmp.Next
}
// 旋转后没变化
if k%len == 0 {
return head
}
// 走到k+1的位置,这样当fast到最后一个元素时,slow位于倒数k的前面
for i:=1; i<=k%len; i++ {
fast = fast.Next
}
// 找到倒数k前面的位置
for fast.Next != nil {
slow = slow.Next
fast = fast.Next
}
// 这是倒数k的节点,要返回的头结点
newlist := slow.Next
slow.Next = nil //断尾,否则是个环形链表了
fast.Next = head
return newlist
}