【leetcode刷题】递归专题

递归专题

  • 一、汉诺塔问题
    • 1、题目描述
    • 2、代码
    • 3、解析
  • 二、合并链表
    • 1、题目描述
    • 2、代码
    • 3、解析
    • 4、总结
  • 三、反转链表
    • 1、题目描述
    • 2、代码
    • 3、解析
  • 四、两两交换链表中的结点
    • 1、题目描述
    • 2、代码
    • 3、解析
  • 五、Pow(x, n)
    • 1、题目解析
    • 2、代码
    • 3、解析


一、汉诺塔问题

1、题目描述

leetcode链接
【leetcode刷题】递归专题_第1张图片

2、代码

class Solution 
{
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) 
    {
        dfs(A, B, C, A.size());
    }
    void dfs(vector<int>&A, vector<int>& B, vector<int>& C, int n)
    {
        // 出口条件
        if(n == 1)
        {
            C.push_back(A.back());
            A.pop_back();
            return;
        }
        // n > 1时候
        // 1、A上的n-1个盘子通过C到B
        dfs(A, C, B, n - 1);
        // 2、A盘子push给C盘子
        C.push_back(A.back());
        A.pop_back();
        // 3、B上的n-1个盘子通过A到C
        dfs(B, A, C, n - 1);
    }
};

3、解析

我们最关键的在于我们要用宏观的角度去看问题,这个汉诺塔问题其实不难,思路来讲很简单,但我们需要明确的是为什么能够用到递归?为什么递归那么好用?其用处在哪?
我们一一来进行解答:我们模拟一下这个形式。
【leetcode刷题】递归专题_第2张图片
发现了,这子问题和上面的问题一模一样,每一个子问题之间都是一样的,那么我们就可以用递归来进行解决,只要能够重复子问题,用这个函数头来进行解决的都是用递归来进行解决。

我们继续去解决一个问题,我们从上面这个图上面得到了什么,我们从A柱子上面的n-1个盘子放到B上面,再将B上面的n-1个盘子放到A上,发现了吗?我们都是整个盘子移动的,是整体移动的!

所以我们从宏观上面来讲:

  • 我们的函数头为(重复子问题):
    dfs(x, y, z, n); 即:将x柱子上的盘子借助y这根柱子移动到z上
  • 我们的函数体(只关心某一个子问题在做什么):
    dfs(x, z, y, n-1); 即:将x柱子上的n-1个盘子借助z这根柱子移动到y上
    x.back() - > z; 即:将x柱子上的最后一个圆盘移动到z上
    dfs(y, x, z, n-1); 即:将y柱子上的n-1个盘子借助x柱子移动到z柱子上
  • 递归的出口:
    N=1时候,x.back()->z 即:将x最后一个盘子移动给z柱子

我们模拟一下宏观的步骤:
【leetcode刷题】递归专题_第3张图片

那我们再模拟一下递归展开图(其中的细节为什么是back()而不是[0]?):
【leetcode刷题】递归专题_第4张图片

二、合并链表

1、题目描述

leetcode链接

【leetcode刷题】递归专题_第5张图片

2、代码

class Solution 
{
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) 
    {
        // 1、先写出口
        if(list1 == nullptr)
            return list2;
        if(list2 == nullptr)
            return list1;
        
        // 2、函数体
        if(list1->val <= list2->val)
        {
            list1->next = mergeTwoLists(list1->next, list2);
            return list1;
        }
        else
        {
            list2->next = mergeTwoLists(list1, list2->next);
            return list2;
        }  
    }
};

3、解析

我们依旧考虑子问题的解决,我们发现其大问题和子问题都是一样的,我们下面来模拟一下:
【leetcode刷题】递归专题_第6张图片

4、总结

【leetcode刷题】递归专题_第7张图片

三、反转链表

1、题目描述

leetcode链接
【leetcode刷题】递归专题_第8张图片

2、代码

class Solution 
{
public:
    ListNode* reverseList(ListNode* head) 
    {
        // 出口 -- 叶子结点或者head本身就是0
        if(head == nullptr || head->next == nullptr)
        {
            return head;
        }
        // 进行递归dfs到最后一个叶子结点(深度优先遍历)
        ListNode* newhead = reverseList(head->next);
        // 逆置 -- 这里是执行上一层的head
        head->next->next = head;
        head->next = nullptr;
        return newhead;
    }
};

3、解析

【leetcode刷题】递归专题_第9张图片

四、两两交换链表中的结点

1、题目描述

leetcode链接
【leetcode刷题】递归专题_第10张图片

2、代码

class Solution 
{
public:
    ListNode* swapPairs(ListNode* head) 
    {
        // 出口
        if(head == nullptr || head->next == nullptr)
            return head;

        // 函数体
        ListNode* tmp = swapPairs(head->next->next);
        ListNode* Ret = head->next;
        Ret->next = head;
        head->next = tmp;

        return Ret;
    }
};

3、解析

【leetcode刷题】递归专题_第11张图片

五、Pow(x, n)

1、题目解析

leetcode链接
【leetcode刷题】递归专题_第12张图片

2、代码

class Solution 
{
public:
    double myPow(double x, int n) 
    {
        return n < 0 ? 1.0 / pow(x, -(long long)n) : pow(x, n);
    }

    double pow(double x, long long n)
    {
        if(n == 0) 
        {
            return 1.0;
        }
        double tmp = pow(x, n / 2);
        return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
    }
};

3、解析

【leetcode刷题】递归专题_第13张图片

你可能感兴趣的:(C++刷题,leetcode,深度优先,算法,c++)