题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内 0 <= Node.val <= 100
方法一、迭代
思路总结
为方便对头节点进行处理,使用虚拟头节点来使头节点能与普通节点一样做相同处理,令虚拟头节点dummyhead->next=head
,令cur
表示当前到达的节点,next
表示当前节点的后继节点,temp
记录待翻转节点后继的节点,即原链表dummyhead->node1->node2->temp
翻转后为dummyhead->node2->node1->temp
再令cur = cur->next->next
实现一次局部翻转。
总的来说就是翻转当前节点后继的两个节点,当前节点后移两位,直到当前节点后只有一个节点或没有节点
代码
struct ListNode* swapPairs(struct ListNode* head){
//没有节点或只有一个节点时返回头节点
if(head==NULL||head->next==NULL){
return head;
}
//创建虚拟头节点
struct ListNode* dummyHead=(struct ListNode*)malloc(sizeof(struct ListNode));
dummyHead->next=head;
struct ListNode* cur=dummyHead;
struct ListNode* next=head;
while(cur->next&&cur->next->next){
//临时节点记录下一组节点的头节点
struct ListNode* temp=next->next->next;
//翻转节点
cur->next=cur->next->next;
cur->next->next=next;
next->next=temp;
//cur移动两位,更新next
cur=cur->next->next;
next=cur->next;
}
return dummyHead->next;
}
方法二、递归
思路总结
- 当链表中没有节点或只有一个时不需要交换,直接返回头节点。
- 当链表中至少有两个节点时,可以通过递归实现两两交换。
- 令一组(两两一组)节点中第一个节点为
head
,第二个节点为newhead
即为翻转后的头节点。令newhead->next=head
即实现单位内的翻转,并需要在翻转前与上一个单位递归返回的新头节点newhead
联结head->next=swapPairs(newhead->next)
注意: 要先进行递归再翻转节点。
代码
struct ListNode* swapPairs(struct ListNode* head){
//没有节点或只有一个节点时返回头节点
if(head==NULL||head->next==NULL){
return head;
}
struct ListNode* newhead=head->next;
//联结上一组节点的头节点
head->next=swapPairs(newhead->next);
//翻转本组节点
newhead->next=head;
return newhead;
}
总结
这是一道链表操作的题目,要求交换相邻节点而且不能修改节点内部的值,需要使用迭代和递归两种方法来解决。
对于迭代方法,我们需要引入虚拟头节点,然后从虚拟头节点开始遍历链表,每次处理相邻的两个节点进行交换。具体实现上,我们需要记录当前节点、下一个节点以及待翻转节点的后继节点,通过修改指针指向来完成翻转。最后,我们将虚拟头节点的下一个节点返回即可。
对于递归方法,我们可以将链表分组为两个节点一组,然后递归处理每组中的节点,最后再将所有组合并起来得到最终结果。具体实现上,我们首先判断链表是否为空或者只有一个节点,如果是直接返回头节点即可;否则,我们可以按照题目要求,将链表分为两个节点一组,第一个节点为head
,第二个节点为newhead
,通过递归处理newhead->next
,并将其作为新的头节点与head
相连即可。
总的来说,这道题目较为简单,但需要对链表操作有一定的掌握程度,能够熟练地使用迭代和递归两种方法来解决问题。