【LeetCode链表#9】图解:两两交换链表节点

两两交换链表中的节点

力扣题目链接(opens new window)

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

24.两两交换链表中的节点-题意

思路

这里还是要应用虚拟头节点,不然交换链表头节点的操作会与交换其他节点时不同

交换的过程其实不难理解,但是代码实现过程需要注意很多细节

下面是交换过程的图解

首先,定义一个虚拟头节点

并让当前指针cur指向dummy head【注意:cur一定要在需要操作的两个节点之前】

然后按途中顺序将对应节点的next指好即可

注意:虽然画图我们很好理解,但是在操作过程中有很多细分步骤,如果直接上手写代码会很困惑

例如,当dummy指向节点2(也就是cur.next.next)后,dummy与原来的节点1就断开连接了

此时再想通过cur去寻找到节点1(cur.next)就行不通了,进而节点2也就无法指向节点1,步骤②无法继续进行

与翻转链表时类似,我们需要一个临时节点temp先去保存节点1

让节点2通过指向temp的方式找到节点1

ps:为什么不存节点2?因为步骤①之后节点2就已经是cur.next了,而dummy是不会变的,所以怎么都能找到节点2

当节点2指向temp(储存有cur.next)后,节点2与原来的节点3就断开连接了

同理,我们应该把节点3也用临时节点保存,这里用temp1保存

于是节点2指向节点3的过程就变成了:

temp1是节点3的备份,它后面还是和节点4连着,所以不用担心找不到节点4

至此,节点1与节点2完成了交换,cur移动到cur.next.next(即交换后此处为节点1,是什么节点并不重要,反正待会交换的又不是当前cur指向的节点,而是后两个节点),展开后的结果如下:

链表节点数为奇数时,结束条件:cur.next.next = null

链表节点数为偶数时,结束条件:cur.next = null

代码

Java版

思路通过画图可以很好理解,但是代码实现又有很多坑

class Solution {
    public ListNode swapPairs(ListNode head) {
        //定义虚拟头节点
        ListNode dummy = new ListNode(0);
        dummy.next = head;//虚拟头节点指向head
        ListNode cur = dummy;

        //定义临时节点用于保存节点1、3
        ListNode temp;
        ListNode temp1;
        

        //遍历链表
        //注意这里的结束条件,链表节点数为奇偶情况下是不同的
        //需要先验证cur.next再验证cur.next.next
        //要不然如果是偶数个节点你先验cur.next.next直接就空指针异常了
        while(cur.next != null && cur.next.next != null ){
            //这里下意识肯定就想开始交换了,但如果不先保存节点就会出现空指针异常
            temp = cur.next;
            temp1 = cur.next.next.next;
            cur.next = cur.next.next;//dummy换2
            cur.next.next = temp;//2换1
            cur.next.next.next = temp1;//1换3,这时候的链表已经是dummy-2-temp,节点3是已经断开找不到了,所以必须用temp1代替节点3
            cur = cur.next.next;//移动cur至新的待交换的两个节点前

        }
        //遍历结束,返回dummy的下一个节点即可
        return dummy.next;
    }
}
c++版

步骤:

1、定义dummy,将其指向head,并设置cur指向dummy

2、定义临时节点保存交换过程中需要记录的节点

3、明确奇偶节点个数下循环终止的条件作为while的循环条件

  • 记录可能丢失的节点
  • 交换节点(自己先画好图,然后照着图写代码)
  • 移动cur到新的待交换的两个节点之前

4、返回dummy节点的下一个节点

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //定义dummy
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;

        ListNode* temp;
        ListNode* temp1;

		//遍历链表
        //注意这里的结束条件,链表节点数为奇偶情况下是不同的
        //需要先验证cur.next再验证cur.next.next
        //要不然如果是偶数个节点你先验cur.next.next直接就空指针异常了
        while(cur->next != nullptr && cur->next->next != nullptr){
            //保存交换节点
            temp = cur->next;
            temp1 = cur->next->next->next;
            //交换
            cur->next = cur->next->next;
            cur->next->next = temp;
            cur->next->next->next = temp1;

            //移动cur至新的待交换的两个节点前
            cur = cur->next->next;

        }
        //因为从始至终,dummy都没有变过
        //因此遍历结束时返回dummy的下一个节点即可
        return dummy->next;
    }
};
技巧

把链表的图画出来,临时节点要存哪个也画好,然后自己尝试用箭头交换节点,就可以理清楚思路了

易错点

1、创建完dummy后记得指向head

2、交换过程中要以cur为参照点来表示参与交换的节点,不要变,例如1换3时不能写成

temp.next = temp1;

3、遍历结束记得移动cur至下下一个节点
(二刷)

4、交换完成后,应该返回dummy的下一个节点(即交换后新链表的头节点)

posted @ 2023-01-17 21:31  dayceng  阅读(284)  评论(0编辑  收藏  举报