[路飞]_前端算法第二十二弹-24. 两两交换链表中的节点(补发)

269 阅读3分钟

https://assets.leetcode.com/uploads/2020/10/03/swap_ex1.jpg

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

示例 2:

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

示例 3:

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

这道题与我们之前做的一道题相似,之前那道题是每相隔K个节点交换一次,这里面只是把K换成了2,所以相比之下,这道题比那道题更简单了,而解题方法也应该更简便,降低时间与空间复杂度。

我们第一个想到的就是递归方法。

递归

递归我们要考虑的就是终止条件,链表中没有节点或者只有一个节点,此时就无法交换。

如果链表中至少有两个节点,则再两两相交之后,链表的头节点变成了第二个节点,第二个节点变成了头节点。此时将链表的头节点改为第三个节点,再进行替换依次递归。更新节点的指针关系,完成整个链表的两两交换。

我们新建一个newHead链表,新链表的头节点为元是链表的第二个节点,则原始链表的其余节点是新链表newhead的头节点的newhead.next 节点,令head.next = swapParise(newHead.next),表示将其余节点继续两两交换,交换后的头节点为head.next,newHead.next =head .直至所有节点都交换完毕。返回最新的newHead。

var swapPairs = function(head) {
		// 终止条件
    if (head === null|| head.next === null) {
        return head;
    }
		// 新建反转后的节点为原始链表的第二个节点
    const newHead = head.next;
		原始链表的下一个节点通过递归一次替换。
    head.next = swapPairs(newHead.next);
		// 新链表的下一个节点为头节点
    newHead.next = head;
    return newHead;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(n),其中 n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。

有递归方法,我们自然就会想到,那么迭代算法要怎么做。

迭代

迭代算法则是先替换前两个,然后将指针指向第三个,再替换前两个,一次向后遍历。

我们先创建一个dummyHead节点,使之等于head,令temp表示当前所到达的节点。初始状态temp=dummyHead。每次都需要交换temp后的两个节点。

终止条件是temp后只有一个节点或者没有节点,则证明无法交换。否则获得temp后的两个节点,node1和node2,更新其两个的指针实现两两交换。

temp=>node1=>node2转变为temp=>node2=>node1

以上交换完成后,令temp = node1再进行下面的交换。

var swapPairs = function(head) {
		// 创建哑结点和遍历节点
    const dummyHead = new ListNode(0);
    dummyHead.next = head;
    let temp = dummyHead;
		// 终止条件temp没有子节点或只有一个
    while (temp.next !== null && temp.next.next !== null) {
				// v找到temp后的两个节点
        const node1 = temp.next;
        const node2 = temp.next.next;
				// 进行两两替换。
        temp.next = node2;
        node1.next = node2.next;
        node2.next = node1;
				// 将temp指向node1,进行下两次替换。直至触发终止条件
        temp = node1;
    }
    return dummyHead.next;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度:O(1)。