zoukankan      html  css  js  c++  java
  • leecode 322. 零钱兑换

    给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

    你可以认为每种硬币的数量是无限的。

    示例 1:

    输入:coins = [1, 2, 5], amount = 11
    输出:3 
    解释:11 = 5 + 5 + 1

    示例 2:

    输入:coins = [2], amount = 3
    输出:-1

    示例 3:

    输入:coins = [1], amount = 0
    输出:0

    示例 4:

    输入:coins = [1], amount = 1
    输出:1

    示例 5:

    输入:coins = [1], amount = 2
    输出:2
    暴力递归解法
    class Solution {
        public int coinChange(int[] coins, int amount) {
    
            //暴力递归解法
            //状态: 目标金额
            //选择:conins 数组中列出的所有硬币面额
            //函数定义:凑出总金额amount, 至少需要coinChange(coins,amount)枚硬币
    
            //base case :amount ==0 时 需要 0 枚硬币 ;amount < 0时 不可能凑出
    
            //coinChange([1,2,5],11)
            //= 1 + min(coinChange([1,2,5],10),coinChange([1,2,5],9),coinChange([1,2,5],6))
    
            //base case
            if(amount ==0) return 0;
            if(amount < 0) return -1;
    
            int res = Integer.MAX_VALUE;
            for(int coin  : coins)
            {
                   //计算子问题的结果
                   int subProblem = coinChange(coins,amount - coin);
                   //子问题无解 则跳过
                   if(subProblem == -1) continue;
                   //在子问题中选择最优解,然后加一
                   res = Math.min(res,subProblem+1);
    
            }
    
            return res == Integer.MAX_VALUE? -1: res;
    
        }
    }

     可以优化,有计算重复节点:

    class Solution {
    
        //自顶向下递归解法
        
        //备忘录
        int []  memo;
    
        public int coinChange(int[] coins, int amount) {  
            memo = new int[amount +1];
            //memo 数组全部初始化为特殊值
            Arrays.fill(memo,-888);        
            return dp(coins,amount);
        }
    
        private int dp(int [] coins,int amount)
        {
           if(amount == 0) return 0;
           if(amount < 0 ) return -1;
    
           //查询备忘录,防止重复计算
    
           if(memo[amount] != -888)
            {
                return memo[amount];
            }
    
            int res = Integer.MAX_VALUE;
            for(int coin: coins)
            {     //子问题计算结果
                  int subProblem = dp(coins,amount-coin);
                  //子问题无解,跳过
                  if(subProblem == -1) continue;
                  //在子问题中选择最优解,然后加一
                  res = Math.min(res,subProblem +1);
    
            }
            //把计算结果存入备忘录
            memo[amount] = (res == Integer.MAX_VALUE)? -1: res;
            return memo[amount];  
        }
    }

    自底向上,迭代求解

    class Solution {
        //自底向上 迭代求解
        public int coinChange(int[] coins, int amount) {
            int [] dp = new int[amount+1];
    
            //dp数组全部初始化为特殊值 amount +1
            Arrays.fill(dp,amount+1);
    
            //base case
            dp[0] = 0;
            for(int i =0;i<dp.length;i++)
            {
              //内层循环 求所有选择的最小值
              for(int coin : coins)
              {
                   //子问题无解,跳过
                   if(i - coin < 0) continue;
                   //状态转移
                   dp[i] = Math.min(dp[i],1+dp[i-coin]);
              }
            }
            return (dp[amount] == amount + 1) ? -1:dp[amount];
    
        }
    }
  • 相关阅读:
    iOS万能跳转界面的方法
    CocoaPods版本更新
    iOS--开发小技巧(持续更新)
    RunTime--手势应用场景(很方便)
    牛逼的标签效果(封装好)
    直播点赞动画
    UI基础--自定义UISwitch
    StatusBar 更改状态栏颜色(ios7)
    ios版本更新提示
    IOS 两个UIImage 合成一个Image
  • 原文地址:https://www.cnblogs.com/kpwong/p/14655621.html
Copyright © 2011-2022 走看看