题目:给定数组arr,arr中的值可以重复,其中每个值代表一张货币,因此不能重复使用。给定一个数aim,求组成aim的最少货币数。
例:
arr=[5,2,3],aim=0,不用任何货币就能组成0元,返回0。
arr=[5,2,3],aim=20,由于不能重复使用,5+2+3<20,不能组成,返回-1。
arr=[5,2,5,3],aim=10,2张5元的可以组成10元,且张数最少,返回2。
实现:生成M*(aim+1)的矩阵dp,dp[i][j]的含义是,在任意使用arr[0,..i]货币的情况下(每个值仅代表一张货币),组成钱数j的最少货币数。
- 对于dp的第一列,即dp[0, M-1][0],表示需要组成的钱数为0时,需要的最少货币数,由于不需要任何货币就可以组成0,所以dp[0,…M-1][0]=0
- 对于dp的第一行,即dp[0][1,…aim],表示只能只用货币arr[0]的情况下,组成钱数j的最少货币数,只有当j=arr[0]的地方,才找得开(注意一张货币只能使用一次)。其它找不开的地方一律用Integer.MAX_VALUE(2^31-1=2147483647)。
- 对于非第一行第一列,dp[i][j]可能来自以下两种情况。
1)任意使用arr[0,..i]货币包括任意使用arr[0,..i-1]货币,所以dp[i][j]可能等于dp[i-1][j]。
2)由于arr[i]只有一张不能重复使用,考虑dp[i-1][j-arr[i]](返回到上次未使用arr[i]的地方,即第[i-1]行),这个值代表可以任意使用arr[0,..i-1]情况下,组成钱数j-arr[i]所需的最小张数。从钱数为j-arr[i]到钱数为j,只需要加上当前货币arr[i]。所以dp[i][j]可能等于dp[i-1][j-arr[i]]+1。
最终得到:
dp[i][j]=min{dp[i-1][j],dp[i-1][j-arr[i]]+1}
1 | /** |
1 | //对上面的函数进行空间压缩优化 O(aim) |