原文
给定一个链表,在一定时间内反转这个链表的结点,并返回修改后的链表。
如果结点数不是K的倍数,那么剩余的结点就保持原样。
你不应该在结点上修改它的值,只有结点自身可以修改。
只允许使用常量空间。
例如
给定链表: 1->2->3->4->5
对于 k = 2,你应该返回: 2->1->4->3->5
对于 k = 3,你应该返回: 3->2->1->4->5
翻译
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5
分析
updated at 2016/08/14
题目要求是每K个节点进行一次逆序,不足K个节点不进行逆序。
那么,这个问题可以分解成2个小问题:
1,找出这里所有的“每K个节点”,如何找?
2,对这K个节点进行局部的逆序,怎么逆?
其实都不难,我们拆分成小问题就好解决了。
比如说K等于3,链表如下:
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> NULL
设当前节点为current,其在1上,再走K-1步,到达3,这时候将其用reverse函数进行局部逆序,怎么逆?先不管,抽象出来。这时候链表如下:
3 -> 2 -> 1 -> 4 -> 5 -> 6 -> 7 - > NULL
之前我们的head是在1上,现在局部逆序之后,它就在1上了。这时候我们使用
head->next = reverseKGroup(start, k);
这里的start也就是即将第二次开始逆序时的head,也就是我所示链表中的4。关键一点是通过这一步,将其作为递归不断的进行下去。
是个递归都要有终止的条件,这里的条件是什么?
只要后续链表中的节点能够大于或等于K,我们就得将局部逆序进行下去,那么如果小于K呢?那自然就不用进行下去了,返回当前的head。什么样叫进行不下去呢,当前current为NULL的时候。
对于我举的例子,当第二次逆序完成后,head是4(6 -> 5 -> 4),start是7。我们就将7(这个序列的头部head)返回作为head(当前是4)的next。
Ok,第一个问题解决了,第二个问题,局部逆序。
前面曾有篇文章介绍过逆序: LeetCode 206 Reverse Linked List(反转链表)(Linked List)(四步将递归改写成迭代)(*)
ListNode* reverseList(ListNode* head) {
ListNode* newHead = NULL;
while (head) {
ListNode* nextNode = head->next;
head->next = newHead;
newHead = head;
head = nextNode;
}
return newHead;
}
这是递归的版本,如果要用迭代的可以去看看这篇博客,正好还讲了如何将递归改写成迭代。
现在这个版本是将整个链表进行逆序,如果想要局部的逆序,其实很简单。通过观察我们发现,这里的结束条件,是head为空的时候,也就是到最后一个节点了,如果我们将其条件改成
while (start != end)
因为start(也就是上面代码中的head)会一直往后走,所以肯定会等于end,这时候递归就停止了,问题也就解决了。
代码
class Solution {
public:
ListNode* reverseKGroup(ListNode *head, int k) {
ListNode *current = head;
for (int i = 0; i < k; ++i) {
if (!current) return head;
current = current->next;
}
ListNode *newHead = reverse(head, current);
head->next = reverseKGroup(current, k);
return newHead;
}
ListNode* reverse(ListNode *start, ListNode *end) {
ListNode *head = end;
while (start != end) {
ListNode *tmp = start->next;
start->next = head;
head = start;
start = tmp;
}
return head;
}
};