Skip to content

两两交换链表中的节点

约 682 字大约 2 分钟

递归后序迭代虚拟节点

2025-02-25

24. 两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

img.png

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100]
  • 0 <= Node.val <= 100

递归

class Solution {
    // 定义函数 swapPairs,用于交换链表中每两个相邻节点
    public ListNode swapPairs(ListNode head) {
        // 如果链表为空或只有一个节点,直接返回该节点(递归终止条件)
        if (head == null || head.next == null) {
            return head;
        }
        
        // 记录新头节点,即原链表的第二个节点
        ListNode newHead = head.next;
        // 递归调用 swapPairs 函数,处理从新头节点的下一个节点开始的链表部分
        // 将当前节点的 next 指向递归返回的结果(即交换后的子链表的头节点)
        // 注意是newHead.next而不是head.next!
        head.next = swapPairs(newHead.next);
        // 将新头节点的 next 指向当前节点,实现这两个节点的交换
        newHead.next = head;
        
        // 返回新的头节点
        return newHead;
    }
}
  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(n),其中 n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。

迭代+虚拟节点

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 创建一个虚拟节点(dummy node),并将其next指向head。这样可以避免处理头结点的特殊情况。
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;

        // temp 是构建节点
        ListNode temp = dummyHead;
        // 当 temp 的后两个节点都不为空时,继续进行交换
        while (temp.next != null && temp.next.next != null) {
            // 定义要交换的两个节点 node1 和 node2
            ListNode node1 = temp.next;
            ListNode node2 = temp.next.next;

            // 进行交换
            temp.next = node2;          // 将 temp 的下一个节点指向 node2
            node1.next = node2.next;    // 将 node1 的下一个节点指向 node2 的下一个节点,这行和下一行的代码的顺序不能错
            node2.next = node1;         // 将 node2 的下一个节点指向 node1

            // 将 temp 移动到 node1,即前进两位,以准备交换下一对节点。重点。
            // temp -> node2 -> node1 -> ...
            temp = node1;
        }

        // 返回新的头结点
        return dummyHead.next;
    }
}
  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(1)。