美文网首页
LeetCode322. 凑零钱,使用三种方式解决

LeetCode322. 凑零钱,使用三种方式解决

作者: lifefruity | 来源:发表于2021-03-12 17:00 被阅读0次

    动态规划是最优的,它自底向上来解决问题

    <?php 
    
    //leetcode 322. 零钱兑换
    //func2([1,2,5], 38) 比 func([1,2,5], 38) 快多了,但是func2运行 func2([186,419,83,408], 6249)会很慢,所以继续优化,使用动态规划
    
    //方法1. 暴力无脑递归求解
    function func($coins, $amount){
        if($coins && !$amount){
            return 0;
        }
        if(count($coins) <= 0 || $amount < 0){
            return INF;//这里不能用-1,不然的话有问题,因为-1肯定是最小的。求最小值,所以初始化为比较大的数
        }
        if(count($coins) >= 1 && in_array($amount, $coins)){
            return 1;
        }
        
        //echo $amount."--".implode(',', $coins)."\n";
        
        $result = INF;
        for($i = 0; $i < count($coins); $i++){
            $a = 1 + func($coins, $amount - $coins[$i]);    //选 注意需要加1
            $result = min($a, $result);
        }
        
        return $result;
    }
    
    //方法2. 带备忘录的递归
    $memory = [];
    function func2($coins, $amount){
        global $memory;
        if(isset($memory[$amount])){
            //echo $amount."\n";
            return $memory[$amount];
        }
        if($coins && !$amount){
            return 0;
        }
        if(count($coins) <= 0 || $amount < 0){
            return INF;//这里不能用-1,不然的话有问题,因为-1肯定是最小的。求最小值,所以初始化为比较大的数
        }
        if(count($coins) >= 1 && in_array($amount, $coins)){
            return 1;
        }
        
        
        
        $result = INF;
        for($i = 0; $i < count($coins); $i++){
            $a = 1 + func2($coins, $amount - $coins[$i]);   //选 注意需要加1
            $result = min($a, $result);
        }
        
        if($result != INF){
            $memory[$amount] = $result;
        }
        
        return $result;
    }
    
    
    //方法3. 动态规划[用了1,3,5面值的钱]
    //f(i) = min{ 1 + f(i - 1), 1 + f(i - 3), 1 + f(i - 5) }
    
    
    function func3($coins, $amount){
        for($i = 1; $i <= $amount; $i++){
            $dp[$i] = INF;//初始化为最大,方便后面用最小值取值来使用
        }
        $dp[0] = 0;
        
        for($i = 1; $i<= $amount; $i++){
            /*
            这段foreach 其实是 f(i) = min{ 1 + f(i - 1), 1 + f(i - 3), 1 + f(i - 5) } 的简化
            */
            foreach($coins as $coin){
                //当前凑n元,但是硬币有coin面值 
                if($coin > $i){
                    continue;
                }
                $dp[$i] = min($dp[$i], 1 + $dp[$i - $coin]);
            }
    
        }
        return $dp[$amount];
    }
    
    $result = func2([186, 419, 83, 408], 6249);
    //$result = func3([1, 3, 5], 28);
    var_dump($result);
    
    

    相关文章

      网友评论

          本文标题:LeetCode322. 凑零钱,使用三种方式解决

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