牛客 BM70 兑换零钱

牛客 BM70 兑换零钱:

题目:给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。
如果无解,请返回-1.

数据范围:数组大小满足 0≤n≤100000≤n≤10000 , 数组中每个数字都满足 0<val≤100000<val≤10000,0≤aim≤50000≤aim≤5000

要求:时间复杂度 O(n×aim)O(n×aim) ,空间复杂度 O(aim)O(aim)。

思路

这题的思路说实话,不在动态规划题组里,我还真想不到。也算是投个巧吧。
设f(aim)为题解,那么在拿到aim的目标时,必定会出现一个情况就是,拿到给定数额中的一个后,达到aim这个状态。假设给定数组为{a1,a2,a3,……,an}。于是f(aim) = min(f(aim – a1), f(aim – a2), ……,f(aim – an)) + 1;当然上述基于aim大于所有给定的数据an。
所以这就关联上动态规划了,将求取当前状态转换为求取子状态。所以构建数组dp[aim+1]初始状态dp[0] = 0; 意思就是当aim=0的时候,只需要取0个硬币就能完成。而dp[aim]和dp[aim-an]之间的关系就是,dp[aim] = min(dp[aim – an] + 1, dp[aim]);而an就是数组{an}中的成员,即arr中的成员,所以an = arr[n];于是上述关系可进一步转换为:
dp[aim] = min(dp[aim – arr[n]] + 1, dp[aim]);
再加上前提,aim肯定要大于arr[n], 才需要考虑该不该拿这个硬币。

代码

于是给出方案代码:

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 最少货币数
     * @param arr int整型一维数组 the array
     * @param aim int整型 the target
     * @return int整型
     */
    public int minMoney (int[] arr, int aim) {
        // write code here
        int size = arr.length;
        int[] dp = new int[aim+1];
        for(int i = 0; i <= aim; i++) {
			//将dp数组成员都初始化为aim+1,因为最多的方案就是aim个硬币
			//如果出现aim+1,即无法给出aim这个结果的硬币组合方案
            dp[i] = aim + 1;
        }
        dp[0] = 0;
        for(int i = 1; i <= aim; i ++) {
            for(int j = 0; j < size; j++) {
				//要保证当前硬币面额,比当前的目标数额小
                if(i >= arr[j]) {
                    dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
                }
            }
        }
	//当dp[aim] > aim的时候,就说明这肯定是初始化后就没赋值,即无满
//足条件的组合方式
        return dp[aim] > aim ? -1 : dp[aim];
    }
}

给出c++代码:

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 最少货币数
     * @param arr int整型vector the array
     * @param aim int整型 the target
     * @return int整型
     */
    int minMoney(vector<int>& arr, int aim) {
        // write code here
        vector<int> res(aim+1, aim+1);
        res[0] = 0;
        for(int i = 1; i < aim + 1; i++) {
            for(int j = 0; j < arr.size(); j++) {
                if(arr[j] <= i) {
                    res[i] = min(1 + res[i - arr[j]], res[i]);
                }
            }
        }
        return res[aim] > aim ? -1 : res[aim];
    }
};
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值