算法设计与分析 第十二周
k个一组翻转链表
1 题目描述
2 选题原因
讲道理这个周确实没讲啥东西…秉承着随机的原则,在首页闭着眼睛点了一下鼠标,选中了这道题。
3 题目分析及算法
3.1 常规分析
分析这道题目,其实是比较简单的。涉及的操作无非就是节点的转移,思考清楚就没有太大的难度。
看这道题,说白了就是将不同段的节点颠倒过来,其实实现起来很简单。我们先看一段链表的倒置
。
当我们要倒置的时候,应该是从头节点开始,依次将头节点放在最后。例如上图,我们从
1
开始,先使用一个指针指向2
,接着将1
节点放在队列的最后(该节点下一个节点稍后会说),接着,将头节点更新为指针指向的节点(即节点2
)。
算法如下:
FOR i = 1: k
temp = head -> next;
head -> next = tail;
tail = head;
ENDFOR
3.2 问题所在
接下来,我们要考虑的问题是:先调换前面的组还是先调换后面的组。
仔细观察一下。当前组的首节点会被放在最后,和下一个组的首节点相接,而下一组的首节点是什么?取决于我们的调换顺序。如果我们从前往后调换,那么这一组会在下一组首节点被放在最后之前连接上!而如果我们从后往前调换,就会在下一组调换完成连接上节点,也正是正常顺序!
4 关键代码
4.1 组内节点调换
//反转节点
while (count > 0) {
//next 下一个头节点
//next_head 下一个要放在最后的节点
ListNode* next = head->next;
head->next = next_head;
next_head = head;
head = next;
count--;
}
4.2 递归的从后向前调换
while (next_head != NULL && count != k) {
next_head = next_head->next;
count++;
}
//递归后面的组先反转,用反转后新的头作为自己尾节点的下一个节点
if (count == k) {
next_head = reverseKGroup(next_head, k);
}
5 运行结果
6 源代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* next_head = head; //标记下一组要反转的位置
int count = 0; //标记当前组的节点数
//找到下一组节点
while (next_head != NULL && count != k) {
next_head = next_head->next;
count++;
}
//递归后面的组先反转,用反转后新的头作为自己尾节点的下一个节点
if (count == k) {
next_head = reverseKGroup(next_head, k);
//反转节点
while (count > 0) {
//next 下一个头节点
//next_head 下一个要放在最后的节点
ListNode* next = head->next;
head->next = next_head;
next_head = head;
head = next;
count--;
}
//指向新的头
head = next_head;
}
return head;
}
};