如何在此递归方法中添加备忘录?

问题描述

我正在尝试解决硬币找零问题(https://leetcode.com/problems/coin-change),并提出了以下递归方法

class Solution {
    public int coinChange(int[] coins,int amount) {
        int[] min = new int[1];
        min[0] = Integer.MAX_VALUE;
        recur(coins,amount,min,0);
        min[0] = min[0]==Integer.MAX_VALUE?-1:min[0];
        return min[0];
    }
    private void recur(int[] coins,int amount,int[] min,int coinsUsed){
        if(amount==0){
            min[0] = Math.min(min[0],coinsUsed);
            return;
        }
        if(amount<0){
            return;
        }
        for(int i=0;i<coins.length;++i){
            recur(coins,amount-coins[i],coinsUsed+1);
        }
    }
}

当前时间复杂度为O((coins.length)^ n)。如何添加便笺来改善这一点?

解决方法

通常,自上而下的记忆会变得有些复杂。一种简单的方法是使用二维数组并自底向上解决问题。假设您有n个面额(从1到n的索引)且总和为S。令T [n] [S]是您需要加总S的最小硬币数量,而v [n]是硬币n的值。

使用硬币n或不使用硬币n都有两种选择。如果你不这样做 那么T [n] [S] = T [n-1] [S]。如果这样做,则T [n] [S] = 1 + T [n] [S-v [n]],因为您不知道哪个是 那就好了

T [n] [S] = min(T [n-1] [S],1 + T [n] [S-v [n]])。 对于所有n都是如此,因此我们得到了递归公式。

T [i] [s] = min(T [i-1] [s],1 + T [i] [s-v [i]])

现在考虑边界条件

  1. 如果i = 1,则所有0的T [1] [s] = s
  2. T [i] [0] = 0表示1
int x,y;
int T[n+1][S+1];
//initialization
for(y=0;y<=S;y++)
   T[1][y]=y;
for(x=0;x<=n;x++)
   T[x][0]=0;
//solution
for(x=2;x<=n;x++){
   for(y=0;y<=S;y++){
       if (v[x]>= y )
           T[x][y]=min(T[x-1][y],1+T[x][y-v[x]];
       else
             T[x][y]=T[x-1][y];
    }
}