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

这篇具有很好参考价值的文章主要介绍了【算法题解】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]

提示:

  • 链表中节点的数目在范围 [ 0 , 100 ] [0, 100] [0,100]
  • 0 < = N o d e . v a l < = 100 0 <= Node.val <= 100 0<=Node.val<=100

递归解法

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

那么我们只需要交换前两个节点即可,以 head = [1,2,3,4,5,6,7] 为例:

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

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

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

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

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

整体流程为:

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
}
复杂度分析

时间复杂度 O ( N ) O(N) O(N) N N N 为节点个数,每两个节点计算一次,时间复杂度为 O ( 1 ) O(1) O(1)。总共需要计算 ( N + 1 ) / 2 (N + 1) / 2 (N+1)/2次,忽略常数后总时间复杂度为 O ( N ) O(N) O(N)

空间复杂度 O ( N ) O(N) O(N),空间复杂度主要取决于递归调用栈的深度,为 ( N + 1 ) / 2 (N + 1) / 2 (N+1)/2,忽略常数后总空间复杂度为 O ( N ) O(N) O(N)


迭代解法

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

如下图所示:每一个组的交换策略都是一样的。即第二个节点指向第一个节点,第一个节点指向下一组的头节点。

然后需要特别主要的是,因为上一组交换的时候还不知道下一组的结果,所以上一组和下一组的链接可能是错误的,需要在下一组交换完成后,修正一下上下两组的链接,即将上一组的 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


}
复杂度分析

时间复杂度 O ( N ) O(N) O(N) N N N 为节点个数。每次迭代时间复杂度为 O ( 1 ) O(1) O(1) N N N 为偶数时需要迭代 N / 2 N / 2 N/2 次, N N N 为奇数时需要迭代 ( N − 1 ) / 2 (N - 1) / 2 (N1)/2 次,忽略常数后时间复杂度计作 O ( N ) O(N) O(N)

空间复杂度 O ( 1 ) O(1) O(1)。常数级空间复杂度,只开辟了固定个数的几个变量。文章来源地址https://www.toymoban.com/news/detail-476831.html

到了这里,关于【算法题解】35. 两两交换链表中的节点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 两两交换链表中的节点【链表】

    Problem: 24. 两两交换链表中的节点 假如要交换1号节点和2号节点: 0-1-2-3变成 0-2-1-3就行了。 时间复杂度: O ( n ) O(n) O ( n ) 空间复杂度: O ( 1 ) O(1) O ( 1 )

    2024年02月01日
    浏览(44)
  • 链表-两两交换链表中的节点

    给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

    2024年01月16日
    浏览(40)
  • 两两交换链表中的节点

     你存在,我深深的脑海里~ 这个题有点类似于反转一个单链表,不同的地方在于这个题不全反转,所以我们不同的地方在于此题多用了一个prve指针保存n1的前一个节点,以及头的改变,用newhead保存一个新的头,其他都大同小异,参考:反转一个单链表 个人主页:Lei宝啊 愿所

    2024年02月12日
    浏览(36)
  • 24. 两两交换链表中的节点

    2024年02月07日
    浏览(45)
  • 【LeetCode热题100】【链表】两两交换链表中的节点

    题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode) 实际上是两个两个一组颠倒顺序,可以用k=2使用【LeetCode热题100】【链表】K 个一组翻转链表-CSDN博客 但可以更简单,就先看两个,先取第二个的指针,递归颠倒第二个后面的节点,链接到第一个节点上,然后把第一个节

    2024年04月13日
    浏览(77)
  • LeetCode24.两两交换链表中的节点

    力扣题目链接

    2024年01月20日
    浏览(42)
  • LeetCode刷题---两两交换链表中的节点

    个人主页:元清加油_【C++】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏:                   前言:这个专栏主要讲述递归递归、搜索与回溯算法,所以下面题目主要也是这些算法做的   我讲述题目会把讲解部分分为3个部分: 1、题目解析 2、算法原理思路讲解  3、

    2024年02月05日
    浏览(53)
  • 算法刷题Day4 两两交换链表中的节点+删除链表的倒数第N个结点+链表相交+环形链表

    使用dummy节点可以极大地简化过程 有个地方折磨了我有一会儿,是粗心导致的,而且提示的错误也很难发现是哪里导致的。就是在case为 head = [1], n = 1 时,最后释放了 tmp 之后(此时 tmp 刚好指向 head ,我还 return head; ,意思就是操作了已经被我释放的内存, leetcode 就报错了

    2024年02月09日
    浏览(49)
  • 【每日一题】24. 两两交换链表中的节点

    给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 示例 2: 示例 3: 提示: 链表中节点的数目在范围 [0, 100] 内 0 = Node.val = 100 思路:纯纯手动模拟。使用一个节点p

    2024年02月14日
    浏览(39)
  • 【LeetCode-中等题】24. 两两交换链表中的节点

    图解: 思路: 设置一个哑结点,作为第一次交换的落脚点 设置落脚点往后两个节点 执行交换,并且让后面的那个节点指向下一次交换的左节点 最后更新落脚点,进行下次循环, 一旦temp.next.next 或者 temp.next 为null,说明落脚点后面的节点不满足两两交换的条件

    2024年02月10日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包