递归-24.两两交换链表中的节点-力扣(LeetCode)

个人主页1白天的黑夜1-CSDN博客

专栏:力扣刷题录_1白天的黑夜1的博客-CSDN博客企鹅程序员:Linux 系统与网络编程_1白天的黑夜1的博客-CSDN博客

目录

一、题目解析

[1、链表中节点的数目在范围 [0, 100] 内](#1、链表中节点的数目在范围 [0, 100] 内)

[2、0 <= Node.val <= 100](#2、0 <= Node.val <= 100)

3、只能进行节点的交换,不能修改节点内部的值

二、算法原理

解法:递归

以宏观视角待递归

通过上面的图片,我们可以知道需要经过三个阶段

1、将前两个节点后的链表通过递归函数进行两两交换,并返回头指针

2、保存第二个节点的指针,用于做新的头指针

3、将前两个节点交换,最后链接上递归函数的头指针,返回新的头指针

如何编写递归代码?

1、重复的子问题->函数头

2、只关心某一个子问题做什么->函数体

3、递归函数的出口

结合视角、如何写递归代码和自己的思路,可以先自己尝试一下编写代码,提升自己的代码能力,题目链接如下

三、代码示例

四、递归展开图

看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!


一、题目解析

1、链表中节点的数目在范围 [0, 100]

2、0 <= Node.val <= 100

3、只能进行节点的交换,不能修改节点内部的值

二、算法原理

本题也有迭代(循环)的解法,本篇博客会着重讲递归的思路与代码,话不多说开始进入正题。

解法:递归

以宏观视角待递归

该题的思路和206. 反转链表 - 力扣(LeetCode)类似,只不过一个是将所有反转,一个是两个两个的反转。先将前两个节点后的链表进行两两反转,然后返回一个头指针。此时通过一个ListNode*类型的变量newhead保存第二个节点,然后将第二个节点的next指向第一个节点,第一个节点的next指向递归函数返回的头指针。

通过上面的图片,我们可以知道需要经过三个阶段

1、将前两个节点后的链表通过递归函数进行两两交换,并返回头指针
2、保存第二个节点的指针,用于做新的头指针
3、将前两个节点交换,最后链接上递归函数的头指针,返回新的头指针

如何编写递归代码?

1、重复的子问题->函数头

我们的重复子问题就是将链表两两交换,需要一个ListNode*的参数,由于需要返回新的头指针,所以返回值类型是ListNode*。所以题目提供的函数可以拿过来用。

2、只关心某一个子问题做什么->函数体

我们需要一个ListNode*型的变量tmp接受递归函数的返回值,还需要一个ListNode*型的变量newhead记录第二个节点的地址也就是head->next,然后将它们三个链接起来,返回newhead这个新的头指针

3、递归函数的出口

如果一个递归函数没有一个出口(返回值),会使递归层数过多导致栈溢出。当节点为空时,直接返回nullptr;如果节点的next为空,则直接返回节点本身。

结合视角、如何写递归代码和自己的思路,可以先自己尝试一下编写代码,提升自己的代码能力,题目链接如下

24. 两两交换链表中的节点 - 力扣(LeetCode)

三、代码示例

这是递归版的代码,可以和下面迭代版的代码做一下比较

cpp 复制代码
class Solution {
public:
    ListNode* swapPairs(ListNode* head)
    {
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return head;
        ListNode* tmp = nullptr;
        tmp = swapPairs(head->next->next);
        ListNode* newhead = head->next;//保存新的头指针
        newhead->next = head;
        head->next = tmp;
        return newhead;
    }
};

迭代版的代码

cpp 复制代码
class Solution {
public:
    ListNode* swapPairs(ListNode* head)
    {
        if(head == nullptr || head->next == nullptr) return head;//0or1个节点
        ListNode* newhead = new ListNode();
        ListNode* tail = newhead;
        ListNode* cur1 = head;
        ListNode* cur2 = head->next;
        ListNode* nnext = cur2->next;
        while(cur1!=nullptr && cur2!=nullptr)
        {
            tail->next = cur2;
            cur2->next = cur1;
            cur1->next = nnext;
            tail = cur1;
            cur1=cur1->next;
            if(cur1 == nullptr) break;
            else cur2 = cur1->next;
            if(cur2 != nullptr) 
                nnext = cur2->next;
        }
        return newhead->next;    
    }
};

可以看的出来递归版的代码量明显变少了,而且少命名了一些变量,节约了空间

四、递归展开图

我们画递归展开图的目的是为了去体会函数执行和调用的过程,所以样例可以不用很复杂。这张递归展开图使用题目给的示例1 1->2->3->4->nullptr

关键点为需要保存第二个节点的地址,不然在更改指针指向时,会丢失节点的地址,导致链接出错;以及函数出口的判断传入的是head->next->next,避免出现对空指针进行访问操作

看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!

相关推荐
1白天的黑夜13 小时前
递归-206.反转链表-力扣(LeetCode)
数据结构·c++·leetcode·链表·递归
靠近彗星3 小时前
3.1 栈
数据结构·算法
Fcy6483 小时前
C++ vector容器的解析和使用
开发语言·c++·vector
无限进步_4 小时前
C语言文件操作全面解析:从基础概念到高级应用
c语言·开发语言·c++·后端·visual studio
_OP_CHEN4 小时前
C++基础:(十五)queue的深度解析和模拟实现
开发语言·c++·stl·bfs·queue·容器适配器·queue模拟实现
sulikey4 小时前
一文彻底理解:如何判断单链表是否成环(含原理推导与环入口推算)
c++·算法·leetcode·链表·floyd·快慢指针·floyd判圈算法
Swift社区4 小时前
LeetCode 402 - 移掉 K 位数字
算法·leetcode·职场和发展