📅  最后修改于: 2023-12-03 15:13:45.779000             🧑  作者: Mango
在这篇文章中,我将向您展示如何在 C++ 中旋转链表。旋转链表意味着将链表的所有节点向右移动k个位置,其中k是非负数。例如,如果您有链表1 -> 2 -> 3 -> 4 -> 5和k = 2,则应将其旋转为4 -> 5 -> 1 -> 2 -> 3。
我们将按照以下步骤实现:
下面是源代码及其解释。
我们将从找到旋转位置的节点开始。如果链表的长度为l,则旋转k次相当于旋转(l-k)%l次。例如,如果链表的长度为5(上面的例子),并且我们要将它旋转2个位置,则它将旋转三次。这个方法可以为我们提供线性时间复杂度。
ListNode* findEnd(ListNode* head) {
while (head && head->next) {
head = head->next;
}
return head;
}
ListNode* rotateRight(ListNode* head, int k) {
if (!head || !head->next || k == 0) return head;
int length = 1;
ListNode* endNode = findEnd(head);
ListNode* newHead;
while (k > 0 && length < INT_MAX) {
newHead = head->next;
head->next = nullptr;
endNode->next = head;
endNode = head;
head = newHead;
k--;
length++;
if (!newHead) {
// 如果我们到达了链表的末尾,从开头再次开始
head = newHead = head->next;
}
}
return head;
}
以上代码中,findEnd
函数返回链表的最后一个节点。rotateRight
函数接受链表头和要旋转的位置k作为输入,并返回新链表的头。在这里,我们使用while
循环将链表旋转k次。
为了确定链表的“前半部分”和“后半部分”,我们需要找到前半部分的最后一个节点。这个节点标志着我们分隔链表的地方。接下来,我们连接新的链表头到前半部分的最后一个节点,并将后半部分的最后一个节点的下一个指向旧的链表头。
ListNode* rotateRight(ListNode* head, int k) {
if (!head || !head->next || k == 0) return head;
int length = 1;
ListNode* endNode = findEnd(head);
k = k % length;
ListNode* newHead;
while (k > 0 && length < INT_MAX) {
newHead = head->next;
head->next = nullptr;
endNode->next = head;
endNode = head;
head = newHead;
k--;
length++;
if (!newHead) {
// 如果我们到达了链表的末尾,从开头再次开始
head = newHead = head->next;
k = k % length;
}
}
ListNode* newEnd = head;
while (newEnd->next) {
newEnd = newEnd->next;
length++;
}
length = length - k;
ListNode* oldEnd = findEnd(head);
oldEnd->next = head;
for (int i = 0; i < length; i++) {
oldEnd = oldEnd->next;
}
ListNode* newHead = oldEnd->next;
oldEnd->next = nullptr;
return newHead;
}
在这个版本的rotateRight
中,我们添加了一个新的变量来跟踪链表的长度。我们通过使用findEnd
函数来“找出”链表的末尾。另外,我们还检查了链表的长度是否大于k,并根据需要更新k。在循环之后,我们重新计算链表的长度,并找到前半部分的最后一个节点。然后,我们将新的链表头连接到最后一个节点,并断开旧的链表头与它的连接。返回新的链表头即可。
最后,我们需要将链表的后半部分连接到前半部分的最后一个节点处。为此,我们需要先找到旧的链表的末尾,然后将它的下一个节点连接到新链表的头部。
最终,在将新链表连接到旧链表的末尾后,我们将返回新链表的头节点即可。
ListNode* findEnd(ListNode* head) {
while (head && head->next) {
head = head->next;
}
return head;
}
ListNode* rotateRight(ListNode* head, int k) {
if (!head || !head->next || k == 0) return head;
int length = 1;
ListNode* endNode = findEnd(head);
k = k % length;
ListNode* newHead;
while (k > 0 && length < INT_MAX) {
newHead = head->next;
head->next = nullptr;
endNode->next = head;
endNode = head;
head = newHead;
k--;
length++;
if (!newHead) {
// 如果我们到达了链表的末尾,从开头再次开始
head = newHead = head->next;
k = k % length;
}
}
ListNode* newEnd = head;
while (newEnd->next) {
newEnd = newEnd->next;
length++;
}
length = length - k;
ListNode* oldEnd = findEnd(head);
oldEnd->next = head;
for (int i = 0; i < length; i++) {
oldEnd = oldEnd->next;
}
ListNode* newHead = oldEnd->next;
oldEnd->next = nullptr;
return newHead;
}
这是我们的完整程序。这种方法的时间复杂度是O(n),因为我们只遍历链表一次。它不需要使用额外的空间,也就是说,它的空间复杂度为O(1)。
感谢您阅读本文,我希望您在将来的代码中能够使用这个技巧!