力扣24.两两交换链表中的节点
题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100
方法1:非递归
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* swapPairs(struct ListNode* head){
if(head==NULL||head->next==NULL) return head;//如果是空链表或者只有一个元素则直接返回
struct ListNode *p=head,*t,*pre=NULL;
if(p->next!=NULL) head=p->next;//直接指定最终的返回位置,即应当是原始第二个节点(不为空)
while(p!=NULL)
{
t=p->next->next;//记录后继节点的下一个位置
if(pre!=NULL) pre->next=p->next;//将前驱节点接到后续节点上,防止断链
pre=p;//将本节点标记为下一次的前驱节点
p->next->next=p;//交换相邻节点,即让相邻节点的后继指针指向当前节点
p->next=t;//当前节点的后继指针指向原后继节点的后继
p=t;//更新当前节点的位置,准备进行下一次交换
if(p!=NULL&&p->next==NULL) return head;//如果更新后只剩下单独一个节点了则不用再交换了,立即返回结果
}
return head;
}
方法2:递归
从第一个节点开始,要通过递归的方式寻找交换之后该节点的下一个节点,规律是:
- 第1个节点的下一个节点是下一个节点的下一个节点,即第3个节点
- 第2个节点的下一个节点是第1个节点
- 以此类推
递归函数中其中一个重大的作用就是为它的上一级调用函数返回需要的节点作为上一级递归中的下一个节点,我们暂存这个节点,在需要结束时返回给上一级函数。
struct ListNode *p=head->next;
同时我们通过调用下一级递归函数的方式来期望获得当前节点交换后连接的下一个节点,注意一次调用的步长为2,即隔一个节点进行下一次调用:
head->next=swapPairs(head->next->next);
并且根据规律,本节点的前驱节点也应改成本节点的原后继节点,即上面暂存的节点P
p->next=head;
最终递归函数完整应写成如下形式:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* swapPairs(struct ListNode* head){
if(head==NULL||head->next==NULL) return head;//如果节点为空或者只剩单一节点终止递归,返回
struct ListNode *p=head->next;//记录当前节点的下一个节点
head->next=swapPairs(head->next->next);
p->next=head;
return p;
}