24. 两两交换链表中的节点(图解递归和双指针)
24. 两两交换链表中的节点
题目描述:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3]
示例 2:
输入:head = [] 输出:[]
示例 3:
输入:head = [1] 输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]
内 0 <= Node.val <= 100
方法一:递归
/** * 1、递归 -- 0ms(100.00%), 40.40MB(5.13%) * <p> * 时间复杂度:O(n) * <p> * 空间复杂度:O(n) */ class Solution { public ListNode swapPairs(ListNode head) { // 如果链表为空或只有一个节点,直接返回头节点,不需要进行交换 if (head == null || head.next == null) { return head; } // 递归调用swapPairs函数,处理剩余的节点,传入头【节点的下一个节点的下一个节点】,返回值赋值给tmp ListNode tmp = swapPairs(head.next.next); // 获取当前节点的下一个节点赋值给p ListNode p = head.next; // 将下一个节点的next指针指向当前节点,完成交换 p.next = head; // 将当前节点的next指针指向递归调用的结果,继续处理剩余的节点 head.next = tmp; // 返回交换后的头节点 return p; } }
代码解析
这个函数的作用是将链表中的每两个相邻节点进行交换,并返回新的头节点。具体步骤如下:
- 首先判断链表是否为空或只有一个节点,如果是,则直接返回头节点,因为不需要交换。
- 然后递归调用
swapPairs
函数,传入参数为当前节点的下一个节点的下一个节点(即跳过了两个节点)。这样可以处理剩余的节点。 - 接下来,获取当前节点的下一个节点,并将其赋值给变量
p
。 - 将
p
的next
指针指向当前节点,完成两个节点的交换。 - 将当前节点的
next
指针指向递归调用的结果,即交换后的剩余节点。 - 最后返回交换后的头节点
p
。
通过递归调用,该函数会逐层向下处理链表,直到到达链表末尾。在每一层递归中,都会交换相邻的两个节点,并将结果传递给下一层递归。最终,当递归到最底层时,所有相邻节点都被成功交换,然后逐层向上返回,最终得到交换后的链表。
图解
示例一:
示例二:
方法二:虚拟头节点 + 双指针
/** * 2、虚拟头节点 + 双指针 -- 0ms(100.00%), 39.89MB(19.62%) * <p> * 时间复杂度:O(n) * <p> * 空间复杂度:O(1) */ class Solution2 { public ListNode swapPairs(ListNode head) { // 创建虚拟头节点,并将其 next 指向原始链表的头节点 ListNode dummy = new ListNode(0, head); // 创建两个指针 pre 和 cur,将 pre 初始化为虚拟头节点 ListNode pre = dummy; // 将 cur 初始化为原始链表的头节点而不是虚拟头节点 ListNode cur = head; // 循环条件:当前节点 cur 和它的下一个节点 cur.next 均不为 null, 不为 null 才能进行交换 while (cur != null && cur.next != null) { // 创建临时节点 tmp,保存下一个节点的引用 ListNode tmp = cur.next; // 将当前节点 cur 的 next 指针指向下一个节点的下一个节点,跳过下一个节点 cur.next = tmp.next; // 将临时节点 tmp 的 next 指针指向当前节点 cur,完成交换 tmp.next = cur; // 将前一个节点 pre 的 next 指针指向交换后的新节点 tmp pre.next = tmp; // 将 pre 移动到下一对相邻节点的前一个节点,即当前节点 cur pre = cur; // 将 cur 移动到下一对相邻节点的当前节点,即下一个节点 cur = cur.next; } // 返回虚拟头节点 dummy 的 next,即完成相邻节点的交换后的链表 return dummy.next; } }
代码解析
-
算法通过维护一个虚拟头节点,利用两个指针
pre
和cur
在链表中遍历,不断交换相邻的节点。 -
这种方式可以避免对头节点的特殊处理
-
循环里主要是三个步骤:报存引用、更换
next
指针指向、移动指针
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix