一. 这题第一眼看到的思路是找到链表倒数第k个节点的位置,从这个位置连接链表前面的部分,从而完成旋转链表.
//通过测试
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
//判断初始条件,注意当k==0时,不需要旋转链表.
if (head == NULL || head->next == NULL || k == 0)
return head;
//利用快慢指针,找到链表倒数第k个节点.
ListNode* slow = head;
ListNode* fast = head;
//首先找到链表的长度.
int length = 0;
while (fast != NULL) {
fast = fast->next;
length++;
}
//因为k有可能会大于链表的长度,
//k%length得到倒数第k个节点的位置.
k = k%length;
fast = head;
//快指针先走k个长度,然后快慢指针一起走.
while (k) {
fast = fast->next;
k--;
}
//找到倒数第k个节点前一个的位置,
//因为我们要将它指向NULL.
while (fast->next != NULL) {
fast = fast->next;
slow = slow->next;
}
ListNode* tmp = slow->next;
//如果k%length==0,则slow指向最后一个节点.
if (tmp == NULL)
//此时更新tmp为头节点.
tmp = head;
else {
//让slow的下一个指向NULL,
//让fast下一个连接链表的头部.
fast->next = head;
slow->next = NULL;
}
//返回tmp节点.
return tmp;
}
};
二. 接下来参考一些大神的做法.
作者:LeetCode
链接:https://leetcode-cn.com/problems/rotate-list/solution/xuan-zhuan-lian-biao-by-leetcode/
直觉:链表中的点已经相连,一次旋转操作意味着:
1. 先将链表闭合成环.
2. 找到相应的位置断开这个环,确定新的链表头和链表尾.
算法实现很直接:
1. 找到旧的尾部并将其与链表头相连 old_tail.next = head,整个链表闭合成环,同时计算出链表的长度 n。
2. 找到新的尾部,第 (n - k % n - 1) 个节点 ,新的链表头是第 (n - k % n) 个节点。
3. 断开环 new_tail.next =NULL,并返回新的链表头 new_head。
直接放上java代码,代码很好理解, 还是看着官方题解的代码比较自然.
class Solution {
public ListNode rotateRight(ListNode head, int k) {
// base cases
if (head == null) return null;
if (head.next == null) return head;
// close the linked list into the ring
ListNode old_tail = head;
int n;
for(n = 1; old_tail.next != null; n++)
old_tail = old_tail.next;
old_tail.next = head;
// find new tail : (n - k % n - 1)th node
// and new head : (n - k % n)th node
ListNode new_tail = head;
for (int i = 0; i < n - k % n - 1; i++)
new_tail = new_tail.next;
ListNode new_head = new_tail.next;
// break the ring
new_tail.next = null;
return new_head;
}
}
- 时间复杂度:O(N),其中 N 是链表中的元素个数.
- 空间复杂度:O(1),因为只需要常数的额外空间.