24.两两交换链表中的结点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
24题原题 https://leetcode-cn.com/problems/swap-nodes-in-pairs/
方法一:遍历整个链表,两两元素间进行交换(用一头结点做辅助作用)
看下图,我们所进行的交换操作实际需要的效果好像是这样:
我们先按这样的思路往下走:那么,按照我之前所说的,刷链表题设一个虚拟头结点是一个好习惯在这道题里就有着很好的体现。这道题里你加一个头结点,会少走不少弯路(因为我上述举的交换这个1,2是一个特例,只牵扯到两个元素的位置交换,我之所以上面说按照我们一开始所讲的思路走下去是为了衬托头结点的过人之处):
最上面:虚假的交换
而这才是真正的交换。
之所以说交换1,2是特例,是因为1之前没有元素,我们不需要考虑位置交换之后的连接。
所以说,小伙子,你只看到了第二层,而你把这道题只想成了第一层,实际上,他是第五层。
先把这里的代码给大家奉上:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if ( head == nullptr || head->next == nullptr )
return head;
ListNode *dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode *pre = dummyHead;
ListNode *cur = head;
ListNode *temp = nullptr;
// 模板:while(...)循环
// 交换当然是需要一对元素,单个元素不在考虑范畴
while ( cur != nullptr && cur->next != nullptr ) {
temp = cur->next;
// 画图分析出的交换step
// 读者可自行分析顺序上是否可以颠倒,画图分析,一目了然
cur->next = temp->next;
temp->next = cur;
pre->next = temp;
// 模板:当对下一轮的pre,cur位置到底处在哪里有疑惑时,想一想pre,cur位置和原来的相对位置相比均应变化2个位置
pre = cur;
cur = cur->next;
}
return dummyHead->next;
}
};
同时,我也给大家看一下按照我最开始的那个思路的错误之处。我的解决办法是第一种情况单独摘出来,之后再按照上述的一般(common)的交换方法。
附代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if ( head == nullptr || head->next == nullptr )
return head;
ListNode *pre = head;
ListNode *cur = head->next;
ListNode *temp = nullptr;
// 单独拎出第一种情况写一段代码
pre->next = cur->next;
cur->next = pre;
// head变化一下
head = cur;
// 并不会出现cur = pre->next不存在的情况,因为这种情况只存在于链表中仅有两个元素,而这个元素已经被我们上面的判断过滤掉了
pre = head->next;
cur = pre->next;
// 共性部分的代码
while ( cur && cur->next ) {
temp = cur->next->next;
pre->next = cur->next;
cur->next = temp;
pre->next->next = cur;
}
return head;
}
};
本题没啥好总结的,链表就是画画图就出来了,了解一些套路(例如头结点,工人指针,单链表变环一类的),刷题就可谓是得心应手。
博客讲解过的Linked-List类的问题的代码均放在GitHub里https://github.com/18260036169/LeetCode-LinkedList