Java动态规划实现硬币找零问题:算法原理与代码解析

凌晨两点半
凌晨两点半
发布时间:2026-10-15| 5人浏览过
原创

动态规划是求解多阶段决策过程最优化的数学方法,其核心在于将大问题分解为子问题并保存中间结果以避免重复计算。本文以经典的“硬币找零”问题为例,在Java中展示如何通过构建状态矩阵,利用回溯思想找出组成特定面额所需的最少硬币数量。

问题描述

假设我们拥有无限数量的几种硬币,面值分别为 [1, 3, 5]。目标是找出能够组成某个目标数目(例如 k)的找零所使用的最少硬币数。

  • 面值2的最少硬币数为2:(1, 1)
  • 面值4的最少硬币数为2:(1, 3)
  • 面值11的最少硬币数为3:(5, 5, 1) 或 (5, 3, 3)

算法分析与状态定义

动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,并将这些子问题的解保存起来(通常保存在数组中)。如果以后在求解较大子问题时需要用到这些子问题的解,就可以直接取出而免去重复运算。

设不同的硬币面值为数组 coin[0, ..., n-1],求面值 k 的最少硬币数 count(k),其递归关系如下:

count(k) = min(count(k - coin[0]), ..., count(k - coin[n - 1])) + 1;

该公式成立的前提条件是 k - coin[i] >= 0 且 k - coin[i] < k。由于要求解 count(k) 时必须已知所有 i < k 的 count(i),这涉及到状态的逐步回溯与填充。

为了清晰展示过程,我们可以创建一个二维矩阵 matrix[k + 1][coin.length + 1]:

  1. 最后一列 matrix[i][coin.length] 用于保存面值 i 的最少硬币总数。
  2. 前面的列 matrix[i][j] 表示使用前 j 种硬币面值时,凑成金额 i 所需的最少硬币数。
  3. 初始化时,使 matrix[0][j] 全部为 0(金额为0不需要硬币)。

第1步:理解状态转移过程

以下是部分状态的推导示意(格式为:k | coin 1 3 5 min):

* k|coin 1  3  5  min
 * 0    0  0  0  0
 * 1    1  0  0  1
 * 2    2  0  0  2
 * 3    3  1  0  3, 1  // 面值3可以用(1,1,1)共3个,或用(3)共1个,取min=1
 * 4    2  2  0  2, 2  // (1,3)或(1,1,1,1),min=2
 * 5    3  3  1  3, 3, 1 // min=1
 * 6    2  2  2  2, 2, 2

第2步:Java代码实现

基于上述逻辑,具体的Java实现代码如下。该方法采用回溯法结合动态规划的填表方式:

public static int backTrackingCoin(int[] coins, int k) {
    // 边界条件检查:硬币数组为空或目标金额小于1
    if (coins == null || coins.length == 0 || k < 1) {
        return 0;
    }
    
    // 创建状态矩阵:行数为k+1(包含金额0到k),列数为硬币种类数+1
    int[][] matrix = new int[k + 1][coins.length + 1];
    
    // 外层循环遍历所有目标金额 i
    for (int i = 1; i <= k; i++) {
        // 内层循环遍历每种硬币 j
        for (int j = 0; j < coins.length; j++) {
            int preK = i - coins[j];
            // 只有当剩余金额不小于0时,才能进行回溯查找
            if (preK > -1) {
                // 尝试使用当前硬币 j,所需数量为 "凑齐preK的最少数量" + 1
                matrix[i][j] = matrix[preK][coins.length] + 1;
                
                // 如果这是第一次计算该金额i的最优解,或者比之前的记录更优,则更新最后一列
                if (matrix[i][coins.length] == 0 || matrix[i][j] < matrix[i][coins.length]) {
                    matrix[i][coins.length] = matrix[i][j];
                }
            }
        }
    }
    // 返回凑齐金额k所需的最少硬币数
    return matrix[k][coins.length];
}

测试与验证

上述代码经过标准测试用例验证,能够正确处理各种硬币组合情况。通过观察 matrix 表中最后一列的变化,可以清晰地看到随着目标金额增加,最少硬币数量的递增规律,体现了动态规划自底向上求解的优势。

以上就是Java动态规划实现硬币找零问题的详细内容,更多关于Java 硬币找零算法优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。