码迷,mamicode.com
首页 > 其他好文 > 详细

LeetCode[Linked List]: Reverse Nodes in k-Group

时间:2014-11-02 09:27:14      阅读:276      评论:0      收藏:0      [点我收藏+]

标签: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个节点即可,剩下的事情都可以让递归帮我们做完。

递归终止条件

递归算法首先需要处理的就是终止条件,我认为有两个:

  1. head为NULL;
  2. 节点个数小于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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!