标签:leetcode 递归 链表 reverse nodes k-group
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
看到这个题,可以确定用递归算法会比较简单:只需要考虑链表的头k个节点即可,剩下的事情都可以让递归帮我们做完。
递归算法首先需要处理的就是终止条件,我认为有两个:
加上一个特殊情况k=1(无需任何转换),可以写出下面的终止条件:
C++ code if (!head || 1 == k) return head;
ListNode *curr = head;
for (int i = 0; i < k; ++i, curr = curr->next)
if (!curr) return head;
但是这里需要注意的一个问题就是上面的代码执行完之后,curr指向的是下一个k-group的第一个节点,有时候我们并不希望这样,而是希望curr指向当前k-group的最后一个节点,这时可以用下面的实现方式:
C++ code if (!head || 1 == k) return head;
ListNode *curr = head;
for (int i = 0; i < k - 1; ++i, curr = curr->next)
if (!curr->next) return head;
对于这个问题,是先递归调用下一组k-group的倒置,还是先进行当前组的倒置,这无关紧要。但是由于上面的终止条件已经帮我们找到了当前组的最后一个节点,可以考虑先递归调用下一组k-group的倒置:curr->next
= reverseKGroup(curr->next, k);
。
接下来的问题就只剩下将k个节点倒置了。比较容易想到也比较笨的方法是(假设k=3)
1->2->3->4
=> 2->1->3->4
=> 2->3->1->4
=> 3->2->1->4
NOTE: 这里面临的比较困难的问题就是头结点的特殊化,即没有节点需要指向头结点。这里采用一个比较巧妙的方法去除头结点的特殊化:创建一个虚拟头结点。这样倒置过程变成了(假设k=3):
0->1->2->3->4 => 0->2->1->3->4 => 0->2->3->1->4 => 0->3->2->1->4
完整的实现代码如下:
C++ code ListNode *reverseKGroup(ListNode *head, int k) {
if (!head || 1 == k) return head;
ListNode *curr = head;
for (int i = 0; i < k - 1; ++i, curr = curr->next)
if (!curr->next) return head;
curr->next = reverseKGroup(curr->next, k);
ListNode *newHead = new ListNode(0);
newHead->next = head;
for (int i = 0; i < k - 1; ++i) {
curr = newHead;
for (int j = 0; j < k - i - 1; ++j, curr = curr->next) {
ListNode *curr1 = curr->next, *curr2 = curr->next->next;
curr1->next = curr2->next;
curr2->next = curr1;
curr->next = curr2;
}
}
return newHead->next;
}
上面代码的时间复杂度是O(N3),显然不是一个好的解法,可以从倒置过程入手:我们已经找到了当前k-group的最后一个节点,只需要将前面的节点挨个儿每次都插到最后那个节点的后面即可(假设k=3):
1->2->3->4
=> 2->3->1->4
=> 3->2->1->4
代码实现如下:
C++ code ListNode *reverseKGroup(ListNode *head, int k) {
if (!head || 1 == k) return head;
ListNode *curr = head;
for (int i = 0; i < k - 1; ++i, curr = curr->next)
if (!curr->next) return head;
curr->next = reverseKGroup(curr->next, k);
ListNode *curr1 = head;
for (int i = 0; i < k - 1; ++i) {
ListNode *curr2 = curr1->next;
curr1->next = curr->next;
curr->next = curr1;
curr1 = curr2;
}
return curr;
}
如果题意未明确指定空间复杂度,可有下面的解法:
C++ code ListNode *reverseKGroup(ListNode *head, int k) {
if (1 == k) return head;
vector<ListNode *> group;
ListNode *curr = head;
for (int i = 0; i < k; ++i, curr = curr->next) {
if (!curr) return head;
group.push_back(curr);
}
group[0]->next = reverseKGroup(group[k - 1]->next, k);
for (int i = 1; i < k; ++i)
group[i]->next = group[i - 1];
return group[k - 1];
}
如果既未指定空间复杂度,又允许修改节点的值,则可有下面的解法:
C++ code ListNode *reverseKGroup(ListNode *head, int k) {
if (1 == k) return head;
ListNode *curr = head;
vector<ListNode *> group;
for (int i = 0; i < k; ++i, curr = curr->next) {
if (!curr) return head;
group.push_back(curr);
}
for (int i = 0; i < (k >> 1); ++i) { // k >> 1 等价于 k / 2
int tmp = group[i]->val;
group[i]->val = group[k - i - 1]->val;
group[k - i - 1]->val = tmp;
}
group[k - 1]->next = reverseKGroup(group[k - 1]->next, k);
return head;
}
LeetCode[Linked List]: Reverse Nodes in k-Group
标签:leetcode 递归 链表 reverse nodes k-group
原文地址:http://blog.csdn.net/chfe007/article/details/40683809