旋转链表
题目描述
Category | Difficulty | Likes | Dislikes |
---|---|---|---|
algorithms | Medium (41.34%) | 1077 | - |
-
Tags
-
Companies
Unknown
给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
**个位置。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
示例 2:
输入:head = [0,1,2], k = 4
输出:[2,0,1]
提示:
- 链表中节点的数目在范围
[0, 500]
内 100 <= Node.val <= 100
0 <= k <= 2 * 109
求解
方法一:双指针
思路与算法
记给定链表的长度为 n,注意到当向右移动的次数 k≥n 时,我们仅需要向右移动 k mod n 次即可。因为每 n 次移动都会让链表变为原状。这样我们可以知道,新链表的最后一个节点为原链表的第 (n−1)−(k mod n) 个节点(从 0 开始计数)。
这样,我们可以先在头节点设置fast和slow两个指针,并让fast指针走(k mod n)步。这样当fast指针到达原链表尾节点时,slow指针刚好到达新链表的尾节点。
具体代码中,我们首先计算出链表的长度 n,然后fast后移(k mod n)步,接着slow和fast同时后移直到fast到达原链表尾节点。这时将fast所指向的节点链接到原链表头节点,将slow所指向节点的下一个节点当作新链表的头节点,即可得到我们所需要的结果。
特别地,当链表长度不大于 1,或者 k 为 n 的倍数时,新链表将与原链表相同,我们无需进行任何处理。
代码
class Solution
{
public:
ListNode *rotateRight(ListNode *head, int k)
{
if (!head)
return head;
// 双指针
ListNode *fast = head;
ListNode *slow = head;
// k mod n
int len = getLength(head);
k %= len;
// 如果k为len整数倍,链表不需要做处理
if (k == 0)
return head;
// fast先走k步
for (int i = 0; i < k; i++)
{
fast = fast->next;
}
// fast和slow后移直到fast到尾节点
while (fast->next)
{
fast = fast->next;
slow = slow->next;
}
// 最后slow->next即为新的头节点
fast->next = head;
ListNode *ans = slow->next;
slow->next = nullptr;
return ans;
}
int getLength(ListNode *head)
{
int len = 0;
while (head)
![请添加图片描述](https://i-blog.csdnimg.cn/direct/e7cec30a84fe4c6490f5acfee370777d.png)
{
len++;
head = head->next;
}
return len;
}
};
复杂度分析
- 时间复杂度:O(n),我们需要遍历该链表两次。
- 空间复杂度:O(1),我们只需要常数的空间存储若干变量。