【算法】递归入门

文章目录

  • 一、基础知识
  • 二、刷题实战
    • 1. 汉诺塔问题
    • 2. 合并两个有序链表
    • 3. 反转链表
    • 4. 快速幂
  • 三、技巧总结

一、基础知识

什么是递归:
函数自己调用自己

什么时候能用递归:
有重复子问题

如何看待递归函数:
看作一个黑盒

如何编写递归代码:

  1. 找到子问题
  2. 设计函数头
  3. 考虑递归出口
  4. 编写函数体

二、刷题实战

1. 汉诺塔问题

题目链接

参考代码:

class Solution 
{
public:
    void hanota(vector<int>& a, vector<int>& b, vector<int>& c) 
    {
        //dfs(x, y, z, n)
        //把 x 的 n 个盘子 借助 y 放到 z

        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;
        }

        //把 a 的 n - 1 个盘子 借助 c 放到 b
        dfs(a, c, b, n - 1);
        
        //把 a 的最后一个盘子 放到c
        c.push_back(a.back());
        a.pop_back();

        //把 b 的 n - 1 个盘子 借助 a 放到 c
        dfs(b, a, c, n - 1);
    }
};

2. 合并两个有序链表

题目链接

题目要求返回新的升序链表的头结点

  1. 找到子问题:返回头结点,合并剩下的两个链表。
  2. 设计函数头:函数返回一个结点,参数是剩下的两个链表。本题给出的接口就满足我们的需求。
  3. 考虑递归出口:当前合并的两个链表,如有一个为空,则返回另一个链表的头结点。
  4. 编写函数体:当前两个结点中较小的当作头结点,头结点的 n e x t next next 指向下一次返回的结点,最后返回这个头结点。

参考代码:

class Solution 
{
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) 
    {
        if(list1 == nullptr) return list2;
        if(list2 == nullptr) return list1;

        auto mi = list1->val <= list2->val ? list1 : list2;
        auto ma = list1->val > list2->val ? list1 : list2;
        mi->next = mergeTwoLists(mi->next, ma);

        return mi;
    }
};

3. 反转链表

题目链接

参考代码:

class Solution 
{
public:
    ListNode* reverseList(ListNode* head) 
    {
        //递归出口 只有0个或1个结点 无需反转 直接返回
        if(head == nullptr || head->next == nullptr) return head;
       	
        //先反转后面的结点
        //递归函数看作黑盒
        auto res = reverseList(head->next);

        //再将当前结点反转
        head->next->next = head;
        head->next = nullptr;

        return res;
    }
};

4. 快速幂

题目链接

参考代码:

class Solution 
{
public:
    double myPow(double x, int n) 
    {
        //递归出口
        if(n == 0) return 1;
        if(n == 1) return x;
        if(n == -1) return 1 / x;
	    
        //先求 x 的 n / 2 次方 x1
        double x1 = myPow(x, n / 2);
        //再求 x 的 n % 2 次方 x2
        double x2 = myPow(x, n % 2);

        return x1 * x1 * x2;
    }
}; 

三、技巧总结

  1. 先画决策树

  2. 注意代码细节

你可能感兴趣的:(算法,算法,深度优先,leetcode,剪枝)