LeetCode322零钱兑换

1,递归+记忆化搜索。

从amount开始向下查找,找到0以后回来更新步数。

我的第一个写法,错误的

java 复制代码
  public int f(int[] coins, int amount, int step){
        if(amount == 0) return step;

        int temp_step = Integer.MAX_VALUE;
        for(int i = 0; i < coins.length; i++){
            int last = amount - coins[i];
            if(last < 0)continue;
            temp_step = Math.min(temp_step, f(coins, last, step + 1));
        }

        return temp_step ;
    }
    public int coinChange(int[] coins, int amount) {
        int res = f(coins, amount, 0);
        return res == Integer.MAX_VALUE? -1 : res;
    }

错误原因

step 这个参数是"外部状态",它让子问题无法复用(也是你之前版本缓存语义错的根源)

你现在虽然没缓存,但 step 的存在本质上说明:

  • 你在求的是"从初始调用累计到现在的总步数"

  • 而经典 coinChange 子问题应该求的是:"凑出 amount 的最少硬币数"(与从哪一层进来无关)

所以只要你想优化(加 memo),就会立刻遇到语义问题:f(amount, step) 不能只用 amount 做 key(因为 step 变了返回值就变了),导致 memo 很难做、或者做了也错。

✅ 正确做法:让递归函数只依赖 amount,返回"从 amount 到 0 的最少硬币数",不要带 step。

用我们能听得懂的话来说,这个step的含义是从初始调用累计到现在的总步数,并不会被路径上的节点更新

正确解法

java 复制代码
    static final int N = (int) (1e4 + 10);
    int[] has_use = new int[N];

    public int coinChange(int[] coins, int amount){
        if(amount == 0) return 0;

        if(has_use[amount] != 0)return has_use[amount];

        int temp_step = Integer.MAX_VALUE;
        for(int i = 0; i < coins.length; i++){
            int last = amount - coins[i];
            if(last < 0)continue;
            int r = coinChange(coins, last);
            if(r == -1)continue;
            temp_step = Math.min(temp_step, r + 1);
        }


        temp_step = (temp_step == Integer.MAX_VALUE) ? -1 : temp_step;
        has_use[amount] = temp_step;

        return temp_step ;
    }

换成自底向上的解法,dp

java 复制代码
  public int coinChange2dp(int[] coins, int amount){
        int[] dp = new int[amount+1];

        for(int i = 1; i <= amount; i++){
            dp[i] = Integer.MAX_VALUE;
            for(int j = 0; j < coins.length; j++){
                int last = i - coins[j];
                if(last < 0)continue;
                if(dp[last] == -1)continue;
                dp[i] = Math.min(dp[i], dp[last] + 1);
            }
            dp[i] = (dp[i] == Integer.MAX_VALUE) ? -1 : dp[i];
        }
        return dp[amount];
    }
相关推荐
Tisfy1 小时前
LeetCode 2685.统计完全连通分量的数量:DFS求每个连通块的边点数
算法·leetcode·深度优先··题解·连通图·全连通分量
海石1 小时前
1次遍历,空间复杂度击败100%,时间复杂度击败85%
算法·leetcode
L歪歪君2 小时前
Apache Doris全链路性能优化实战指南:从架构设计到生产落地
java·开发语言·算法
m0_466525292 小时前
从“算法内卷”到“可信易用” 东软多模态医学人工智能平台开启无代码科研新时代
人工智能·算法
码少女2 小时前
数据结构——冒泡排序及优化
数据结构·算法·排序算法
梦回江东3 小时前
ansible中的主机清单
算法
青梅橘子皮3 小时前
string---入门OJ题(1)
数据结构·算法
qq_454245033 小时前
BasicMethod.Map 设计框架:8 个并行基础模块的数学根基与实现
数据结构·算法·c#
青山木3 小时前
Hot 100 --- 二叉树与递归
java·数据结构·算法·leetcode·深度优先
珠海西格电力4 小时前
数据采集与治理:零碳园区管理系统的 “生命线”
大数据·人工智能·算法·架构·能源