【算法题解】35. 两两交换链表中的节点

这是一道 「中等难度」 的题
https://leetcode.cn/problems/swap-nodes-in-pairs/

题目

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

示例 1:

【算法题解】35. 两两交换链表中的节点
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

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

示例 3:

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

提示:

  • 链表中节点的数目在范围

递归解法

假如除了前面的两个节点,后面的已经两两交换完成,且结果为 swapPairs(head.next.next)

那么我们只需要交换前两个节点即可,以 head = [1,2,3,4,5,6,7] 为例:【算法题解】35. 两两交换链表中的节点

同理,后续链表也认为只需要交换前两个节点,head.next.next 已经交换完毕。逐层调用即为递归。

以Java代码为例,「递归函数」为:

ListNode next = head.next;
ListNode nextHead = next.next;

// 交换
next.next = head;
head.next = swapPairs(nextHead);

「边界条件」head为空或者head.next为空,即后续节点个数不够两个就可以直接返回了。

整体流程为:【算法题解】35. 两两交换链表中的节点

Java 代码实现

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

class Solution {
    public ListNode swapPairs(ListNode head) {

        if(head == null || head.next == null){
            return head;
        }

        ListNode next = head.next;
        ListNode nextHead = next.next;

        // 交换
        next.next = head;
        head.next = swapPairs(nextHead);

        return next;
    }

    
}

Go 代码实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

func swapPairs(head *ListNode) *ListNode {

    if head == nil || head.Next == nil {
        return head
    }


    nextNode := head.Next
    nextHead := nextNode.Next

    // 交换
    nextNode.Next = head
    head.Next = swapPairs(nextHead)


    return nextNode
}

复杂度分析

  • 「时间复杂度」 为节点个数,每两个节点计算一次,时间复杂度为。总共需要计算 次,忽略常数后总时间复杂度为
  • 「空间复杂度」,空间复杂度主要取决于递归调用栈的深度,为 ,忽略常数后总空间复杂度为

迭代解法

首先为了第一组(即前两个节点)和后面组的交换逻辑保持一致,在最前面加入一个 protect 节点,最后直接返回 protect.next 即为答案。

如下图所示:每一个组的交换策略都是一样的。即第二个节点指向第一个节点,第一个节点指向下一组的头节点。【算法题解】35. 两两交换链表中的节点然后「需要特别主要的是」,因为上一组交换的时候还不知道下一组的结果,所以上一组和下一组的链接可能是错误的,需要在下一组交换完成后,修正一下上下两组的链接,即将上一组的 tail 节点指向当前组交换完后的新的 head 节点。

每次往后移动一组,head 节点变为下一组的头节点,tail 变成上一组结果的尾节点。

Java 代码实现

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

class Solution {
    public ListNode swapPairs(ListNode head) {

        if(head == null){
            return null;
        }

        // 保护节点
        ListNode protect = new ListNode(0, head);

        //已迭代过的尾巴节点
        ListNode tail = protect;

        // 当后面至少还有两个节点的时候,需要继续迭代
        while(tail.next != null && tail.next.next != null){
                
            // 交换
            // 上一组的末尾 --> 本组的第二个节点
            // 本组的第二个节点--> 本组的开头

            head = tail.next;
            ListNode secondNode = head.next;
            ListNode nextHead = secondNode.next;

            
            tail.next = head.next;
            head.next.next = head;
            head.next = nextHead;

            tail = head;
        }

        return protect.next;
    }
}

Go 代码实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

func swapPairs(head *ListNode) *ListNode {

    if head == nil || head.Next == nil {
        return head
    }

    protect := &ListNode{0, head}
    tail := protect

    // 当后面至少还有两个节点的时候,需要继续迭代
    for tail.Next != nil && tail.Next.Next != nil {
        // 交换
        // 上一组的末尾 --> 本组的第二个节点
        // 本组的第二个节点--> 本组的开头

        head = tail.Next
        secondNode := head.Next
        nextHead := secondNode.Next

            
        tail.Next = head.Next
        head.Next.Next = head
        head.Next = nextHead

        tail = head;
    }

    return protect.Next


}

复杂度分析

  • 「时间复杂度」 为节点个数。每次迭代时间复杂度为 为偶数时需要迭代 次, 为奇数时需要迭代 次,忽略常数后时间复杂度计作
  • 「空间复杂度」。常数级空间复杂度,只开辟了固定个数的几个变量。


– End –



早上送芒果上学,天空飘着毛毛细雨。芒果有感而发:“爸爸,我也是从天上下下来的,爸爸从里面选了一个最好看的带回家就变成小芒果啦”。哈哈,愉快的一天。


原文始发于微信公众号(i余数):【算法题解】35. 两两交换链表中的节点

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/193815.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!