美文网首页
零钱兑换

零钱兑换

作者: 最困惑的时候就是能成长的时候 | 来源:发表于2019-05-21 16:43 被阅读0次

    题目地址:https://leetcode-cn.com/problems/coin-change/
    题解:

    一.思考步骤

    1.建模

    ①解:<x1,x2...xn>代表了Xi代表了第i种硬币的个数
    ②目标函数:所有金币的价值为总数accout,且数量最少min\{\Sigma_{i=1}^nx_i \}
    ③约束条件:所有的金币价值为accoutaccount = \Sigma_{i=1}^nv_ix_i

    2.子问题优化

    我使用k种硬币,总数为y,那么k=n,y=account的时候是原问题,F_k(y)代表了k种硬币,组成y总数时的最小硬币 数
    ⑴:y>Vk,y>0,k>0

    F_k(y) = min\{F_{k-1}(y),F_k(y-v_k)+1\}
    ⑵:y=0或者k=0
    F_k(y) =0
    ⑶:y<Vk
    F_k(y) =F_{k-1}(y)
    ⑷:y<Vk,且k=1
    F_k(y) =-1

    3.归结公式

    F_k(y) \begin{cases} min\{F_{k-1}(y),F_k(y-v_k)+1\}, &当y>vk,k>0,y>0;\\ 0, &当y=0;\\ F_{k-1}(y),&当y<w_k;\\ ∞,&当k=1,y<w_1或k=0 \end{cases}

    二.伪代码

    dp[][]=new int[n+1][account+1]; 代表了k种,y总量的最小硬币数
    for i=0 →n+1
       dp[i][0]=0;  //条件二
    for j=1 →account+1
       dp[0][j]=∞;  //条件四
    for i=1 →n+1
       for j=1 →account+1
          分成三种情况:
          1.如果j>coins[i],那么说明当前至少有一个硬币,dp[i][j]=min(dp[i][j-coins[i]]+1,dp[i-1][j]);
          2.如果j=coins[i],那么说明当前刚好够一个硬币dp[i][j]=1
          3.如果j<coins[i],那么说明当前的第i种硬币面值过大,应该减少,但是如果i=1的话说明只用第一种硬币无法满足条件,也就是dp[1][j]=∞,不等于1的话  dp[i][j]=dp[i-1][j]
    最后返回dp[n][account]
    

    三.代码

    public int coinChange(int[] coins, int amount) {
            int[][] dp=new int[coins.length+1][amount+1];
            for(int i=0;i<coins.length+1;i++)dp[i][0]=0;
            for(int i=0;i<amount+1;i++)dp[0][i]=Integer.MAX_VALUE;
            for(int i=1;i<coins.length+1;i++){
                for(int j=1;j<amount+1;j++){
                    //情况一
                    if(j>coins[i-1])dp[i][j]=(dp[i][j-coins[i-1]] ==Integer.MAX_VALUE)?dp[i-1][j]:Math.min(dp[i][j-coins[i-1]]+1,dp[i-1][j]);
                    //情况二
                    else if(j==coins[i-1])dp[i][j]=1;
                    //情况三
                    else{
                       if(i==1)dp[i][j]=Integer.MAX_VALUE;
                       else dp[i][j]=dp[i-1][j];
                    }
                }
            }
            if(dp[coins.length][amount]==Integer.MAX_VALUE) {
                dp[coins.length][amount]=-1;
            }
            return dp[coins.length][amount];
        }
    

    四:其它写法

    public int coinChange(int[] coins, int amount) {
            int[] dp=new int[amount+1];
            dp[0]=0;
            for(int i=1;i<amount+1;i++) {
                dp[i]=Integer.MAX_VALUE;
                for(int j=0;j<coins.length;j++) {
                    if(i-coins[j]>=0&&dp[i-coins[j]]+1<dp[i]&&dp[i-coins[j]]!=-1) {
                        dp[i]=dp[i-coins[j]]+1;
                    }
                }
                if(dp[i]==Integer.MAX_VALUE) {
                    dp[i]=-1;
                }
                
            }
            return dp[amount];
        }
    
    这种就是先去计算dp[i]在使用所有硬币的时候的硬币数,然后到dp[amount]的时候比较各个dp[amount-coins[i]]的关系

    相关文章

      网友评论

          本文标题:零钱兑换

          本文链接:https://www.haomeiwen.com/subject/auodzqtx.html