原题链接:https://leetcode.com/problems/swap-nodes-in-pairs/
我在github上的leetcode仓库:https://github.com/cooljacket/leetcodes
题意
把单链表相邻的两个元素,两两交换,只能操作节点,而不能单单交换节点的值。比如1->2->3->4,将变成2->1->4->3(即1和2交换,3和4交换)。
思路
- 对于长度小于2的链表,特判一下,保证下面的算法处理的都是长度至少为2的链表,就不需要对边界做太多的考虑了!
- 长度为偶数这个容易,刚好两两交换;但是奇数个结点呢?那当然是最后一个结点没有人跟它交换,所以就不变了,比如1->2->3变成2->1->3。
- 我把相邻两个结点交换位置,抽象成:把前者从链表中删掉,然后插入到后者的后面去。比如before->A->B->after,先把A拿掉,变成before->B->after,然后把A插入到B的后面,变成:before->B->A->after,是不是容易理解得多?
- 注意根据3中的描述,before应该是一个不为NULL的结点,但是对于头部的两个结点的交换来说,它们并没有before结点,所以也需要特殊处理一下,简单做,就是把前者插入到后者后面就可以了!
- 为什么3中要这么抽象呢?因为我觉得写一堆的赋值next的语句只会把人给绕晕,但是明明链表这种问题就是跟小时候堆积木是一样简单的,所以我想抽象成很容易理解的操作来实现。
代码
/*
问题要求:
1)将单链表相邻两个节点交换;
2)只能使用常数空间;
3)只能改变节点,不能只改变节点的值。
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
// 首先排除空链表和只有一个元素的链表的情况
if (head == NULL || head->next == NULL)
return head;
// 头部的两个元素做特殊处理,交换相当于把头部插入到第二个节点后面而已
// 所以before元素的值是head,而新的头部的值是原来的第二个节点
ListNode *before = head, *newHead = head->next, *tmp;
insertAfter(newHead, head);
// 保证始终都有两个元素可以做交换,因为如果只剩下一个元素,就可以直接终止了
// 在before->A->B->after模型里,交换前,before->next就是指A,before->next->next就是指B
while (before->next != NULL && before->next->next != NULL) {
// 这个交换动作其实可以等价抽象为:将第一个节点拿掉,插入到第二个节点后面!
tmp = deleteAfter(before);
insertAfter(before->next, tmp);
before = tmp;
}
return newHead;
}
void insertAfter(ListNode *node, ListNode *toInsert) {
toInsert->next = node->next;
node->next = toInsert;
}
ListNode* deleteAfter(ListNode *node) {
ListNode *toDelete = node->next;
if (toDelete != NULL)
node->next = toDelete->next;
return toDelete;
}
};