算法(前端):放苹果问题中的动态规划和递归

597 阅读2分钟

前言

  • 算法是衡量一个面试者是否优先的重要指标。花时间和精力去了解掌握常见算法,十分有必要。
  • 在学习算法时,动态规划和递归时常容易被混淆,本文中会尝试做出解答。

题目

来源:放苹果

把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?

注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。
数据范围:0 <= m <= 10 ,1<= n <=10 。

动态规划解题思路:

n 个盘子放苹果的问题可以转化为: n个盘子都有苹果和 n 个盘子至少有一个没有苹果(也就是 n-1 个盘子放 m 个苹果的问题)。

解法一:递归

function dp(m, n){
    if(m==0 || n==1){
        return 1;
    } else if(n > m){
        return dp(m, m)
    } else {
        // n 个盘子放苹果的问题可以转化为: n个盘子都有苹果和 n 个盘子至少有一个没有苹果(也就是 n-1 个盘子放 m 个苹果的问题)
        return dp(m, n-1) + dp(m-n, n)
    }
}

解法二:动态规划的通常解法

function dp(m, n){
   for(let i = 0; i<=m; i++){
       arr[i][1] = 1;
   }
   for(let i = 1; i<=n; i++){
       arr[0][i] = 1;
   }
   
   // n 个盘子放苹果的问题可以转化为: n个盘子都有苹果和 n 个盘子至少有一个没有苹果(也就是 n-1 个盘子放 m 个苹果的问题)
   for(let i =1; i<=m; i++){
       for(let j =2; j<=n; j++){
           if(i>=j){
               arr[i][j]=arr[i][j-1] + arr[i-j][j]
           } else {
               arr[i][j] = arr[i][i]
           }
       }
   }
   return arr[m][n];
}

动态规划

动态规划问题具有三个特征:具有三个特征:最优子结构、无后效性和重复子问题

  • 最优子结构:一般情况下是指的求最优解,比如字符串编辑距离的最短路径问题; 合唱队问题的最少出列数;
  • 无后效性:无后效性指的是某阶段状态一旦确定,就不受之后阶段的决策影响。
  • 重复子问题:分解为很多重复子问题,且必须记住结果,空间换时间。

动态规划和递归的区别

  • 动态规划是一种算法思路,递归是实现手段,维度不同。
  • 递归问题实际上会存在重复计算。数据规模较大时,效率很低。

其他

欢迎大家关注微信公众号:赵公子聊前端