算法——递归的练习

Tips:注意文章中标红的地方,这些都是容易犯错的地方

leecode面试题16.11——跳水板

  • 题目描述:

面试题 16.11. 跳水板
你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。
返回的长度需要从小到大排列。
示例 1
输入:
shorter = 1
longer = 2
k = 3
输出: [3,4,5,6]
解释:
可以使用 3 次 shorter,得到结果 3;使用 2 次 shorter 和 1 次 longer,得到结果 4 。以此类推,得到最终结果。
提示:
0 < shorter <= longer
0 <= k <= 100000

  • 分析:
    咋说呢,分类是分到了递归的这里,但并不觉得递归是个解决本题的最佳方法。
    本题就直接用r[i] = shorter*i + longer*(k-i)来实现就行。
  1. 注意1: 处理两个特殊情况:k值小于等于0、shorter值等于longer的情况。
    k小于等于0这个特殊情况很容易想到,但shorter=longer的情况是真的没想到,测试用例没通过才想到这种情况,当两个值相等时,这个时候输出数组就一个值就是shorter*k,要是还是按照通用方法,最后会输出k个一样的值。如图所示:
    在这里插入图片描述
  2. 注意2: 根据所给的输出示例,给出题目要求的输出,本题的要求就是shorter这个值的个数从大到小去计算。
    比如说这个测试用例,我得到的值是对着,但答案的顺序和要求的有出入,因此观察所给的输入输出示例则能得到要求的值。
    在这里插入图片描述
  • 代码:
class Solution {
public:
    vector<int> divingBoard(int shorter, int longer, int k) 
    {
        vector<int> r;
        if(k<=0)
            return r;
        if(shorter == longer)
        {
            r.push_back(shorter*k);
            return r;
        }   
        for(int i=k;i>=0;i--)
        {
            r.push_back(shorter*i + longer*(k-i));
        }
        return r;
    }
};

leecode1137——第N个泰波那契数

  • 题目描述:
  1. 第 N 个泰波那契数
    泰波那契序列 Tn 定义如下:
    T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
    给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
    示例 1:
    输入:n = 4
    输出:4
    解释:
    T_3 = 0 + 1 + 1 = 2
    T_4 = 1 + 1 + 2 = 4
    示例 2:
    输入:n = 25
    输出:1389537
    提示:
    0 <= n <= 37
    答案保证是一个 32 位整数,即 answer <= 2^31 - 1。

这个名字硬生生的把tribonacci翻译成了中式英语

  • 分析:
  1. 递归肯定是超时了,因为重复的计算太多了,所以需要用到递归的优化:考虑保存重复计算值或者考虑自下而上的递推方法。
  2. 这个题有意思了,刚刚复习的小青蛙跳台阶的优化方法递推方法刚好派上用场。
  • 代码:
    注意: 递推的方式中约束条件的n也要算上!
class Solution {
public:
    int tribonacci(int n) 
    {
        if(n < 2)
            return n;
        if(n == 2)
            return 1;

        int f0 = 0, f1 = 1, f2 = 1;
        int sum123 = 0;
        for(int i=3;i<=n;i++)//注意是i<=n
        {
            sum123 = f0 + f1 + f2;
            f0 = f1;
            f1 = f2;
            f2 = sum123;
        }
        return sum123;
    }
};
  • 补充:python简洁方法,不看函数定义,因为定义给了,你直接写函数内容。把这个贴出来的原因是为了理解三个f1,f2,f3之间的赋值。
class Solution:
    def tribonacci(self, n: int) -> int:
        a, b, c = 0, 1, 1
        for i in range(n) :
            a, b, c = b, c, a+b+c
        return a

leecode面试题 08.05. ——递归乘法

  • 题目描述:

面试题 08.05. 递归乘法
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
示例1:
输入:A = 1, B = 10
输出:10
示例2:
输入:A = 3, B = 4
输出:12
提示:
保证乘法范围不会溢出

  • 分析:
    本题依然用的是递归三要素,真的很好用
  • 代码:
class Solution {
public:
    int multiply(int A, int B) 
    {
        //2. 递归结束的条件 
        if(A==1)
            return B;
        else if(B==1)
            return A;

        //3. 寻找函数的等价关系式
        return A + multiply(A, B-1);
    }
};

leecode698. ——划分为k个相等的子集

  • 题目描述:
  1. 划分为k个相等的子集
    给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。
    示例 1:
    输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
    输出: True
    说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
    提示:
    1 <= k <= len(nums) <= 16
    0 < nums[i] < 10000
  • 分析:
    这个题说实话挺难理解的,抄了大佬的代码,还是理解了很长时间。
    这个实现用了两个函数和一个全局变量:
  1. 函数1实现对原数组的处理,包括计算这个要搜索的总和target=数组总和/k,将数组元素用哈希表进行保存,方便后边用dfs进行搜索,还有就是特殊情况的处理,包括target不存在的情况和数组最大值大于这个target的情况,都是返回false;
  2. 函数2实现dfs深度优先搜索:实现寻找k个target是否能在数组中组合存在。难理解的是核心dfs部分,用了一个for循环取遍历了所有可能的情况。
  • 代码:
class Solution {
public:
    int x=0;
    bool canPartitionKSubsets(vector<int>& nums, int k) 
    {
        int len = nums.size();
        int sum = 0;
        unordered_map<int, int> hashMap;
        int maxNum = 0;
        for(int i=0;i<len;i++)
        {
            sum += nums[i];
            hashMap[nums[i]]++;
            maxNum = nums[i]>maxNum? nums[i]:maxNum;
        }

        int target = sum/k;
        x = target;
        if(sum%k != 0 || maxNum > target)
            return false;

        return dfs(hashMap, k, 0);//DFS搜索x个target看是否存在
    }
    //DFS寻找kNew个target,newTarget是上一个子集剩余的需要寻找的元素
    bool dfs(unordered_map<int, int> &hashMap, int kNew, int newTarget)
    {
        //DFS递归结束条件
        if(newTarget == 0)
        {
            if(kNew == 0)
            {
                return true;
            }    
            else
            {
                return dfs(hashMap, kNew-1, x);//当前子集搜索完毕,搜索下一个
            }
        }
        //DFS搜索target,从数组中最大的值开始搜索
        for(int i=newTarget;i>0;i--)
        {
            if(hashMap[i]>0)
            {
                hashMap[i]--;
                if(dfs(hashMap, kNew, newTarget-i))//递归继续搜索target-i
                    return true;

                hashMap[i] += 1;
            }
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值