当前位置: 首页 > news >正文

每日一题——兑换零钱(一)

@toc

题目描述

给定一个数组 arr,数组中的每个值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张。再给定一个目标金额 aim,要求找出组成 aim 的最少货币数。如果无法组成 aim,则返回 -1

数据范围

  • 数组大小满足 (0 \leq n \leq 10000)
  • 数组中每个数字满足 (0 < val \leq 10000)
  • 目标金额满足 (0 \leq aim \leq 5000)

要求

  • 时间复杂度 (O(n \times aim))
  • 空间复杂度 (O(aim))

示例

示例1

输入

[5, 2, 3], 20

返回值

4

说明

  • 使用 4 张货币(5 + 5 + 5 + 5)可以组成 20。

示例2

输入

[5, 2, 3], 0

返回值

0

说明

  • 目标金额为 0,不需要任何货币。

示例3

输入

[3, 5], 2

返回值

-1

说明

  • 无法用给定的货币组成 2。

参考视频

题解

动态规划

我们可以使用动态规划来解决这个问题。设 dp[i] 表示组成金额 i 所需的最少货币数。状态转移方程如下:

  1. 对于每个金额 i,遍历所有货币面值 arr[j]
  2. 如果 i >= arr[j],则 dp[i] = min(dp[i], dp[i - arr[j]] + 1)

边界条件

  • dp[0] = 0,表示组成金额 0 不需要任何货币。
  • 其他 dp[i] 初始化为一个较大的值(如 5001),表示暂时无法组成该金额。

代码实现

#include <stdio.h>
#include <stdlib.h>

/**
 * 动态规划求解最少货币数
 * 
 * @param arr int整型一维数组,表示货币的面值
 * @param arrLen int,表示货币数组的长度
 * @param aim int整型,表示目标金额
 * @return int整型,表示组成目标金额的最少货币数,如果无法组成则返回-1
 */
int minMoney(int* arr, int arrLen, int aim) {
    // 分配动态规划数组,dp[i] 表示组成金额 i 所需的最少货币数
    int* dp = (int*)malloc((aim + 1) * sizeof(int));
    if (dp == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }

    // 初始化动态规划数组,将所有值设置为一个较大的数(5001,因为题目中 aim 最大为 5000)
    for (int i = 0; i <= aim; i++) {
        dp[i] = 5001;
    }

    // 组成金额 0 所需的货币数为 0
    dp[0] = 0;

    // 动态规划计算每个金额的最少货币数
    for (int i = 1; i <= aim; i++) {
        for (int j = 0; j < arrLen; j++) {
            // 如果当前金额 i 大于等于货币面值 arr[j],以防止dp[i - arr[j]]越界
            if (i >= arr[j]) {
                // 如果 dp[i - arr[j]] 是有效的(不是初始值 5001)
                if (dp[i - arr[j]] != 5001) {
                    // 更新 dp[i] 为 dp[i - arr[j]] + 1 和当前 dp[i] 的最小值
                    dp[i] = (dp[i] < dp[i - arr[j]] + 1) ? dp[i] : dp[i - arr[j]] + 1;
                }
            }
        }
    }

    // 如果 dp[aim] 仍然是初始值 5001,表示无法组成金额 aim,返回 -1
    int result = (dp[aim] == 5001) ? -1 : dp[aim];

    // 释放动态规划数组
    free(dp);

    // 返回结果
    return result;
}

int main() {
    int arr[] = {5, 2, 3}; // 货币面值数组
    int arrLen = 3;        // 货币面值数组的长度
    int aim = 20;          // 目标金额

    int result = minMoney(arr, arrLen, aim); // 调用函数计算最少货币数
    printf("Minimum number of coins: %d\n", result); // 打印结果

    return 0;
}

复杂度分析

  • 时间复杂度:(O(n \times aim)),其中 (n) 是货币数组的长度,aim 是目标金额。我们需要遍历每个金额和每种货币面值。
  • 空间复杂度:(O(aim)),用于存储动态规划数组 dp

总结

本题通过动态规划的方法,将问题分解为子问题,逐步求解。通过状态转移方程,我们可以高效地计算出组成目标金额的最少货币数。如果无法组成目标金额,则返回 -1

相关文章:

  • 【Linux】【进程】epoll内核实现总结+ET和LT模式内核实现方式
  • axios
  • AF3​​​​​​​ get_atom_coords函数解读
  • 火语言RPA--字符串内插入字符串
  • 适配器模式详解(Java)
  • . Unable to find a @SpringBootConfiguration(默认软件包中的 Spring Boot 应用程序)
  • 三、Unity基础(主要框架)
  • 撕碎QT面具(1):Tab Widget转到某个Tab页
  • 数据结构——顺序表与链表
  • 华为昇腾920b服务器部署DeepSeek翻车现场
  • ESP32鼠标驱动(ble hid device_demo)【ESP32指向鼠标】
  • 外贸订货系统的核心功能模块解析
  • 基于fastadmin快速搭建导航站和API接口站点系统源码
  • 深入剖析GC问题:如何有效判断与排查
  • DeepSeek专题:DeepSeek-V1核心知识点速览
  • 国内情智机器人:从“通情达理”到温暖陪伴的跨越
  • UDP通信开发
  • 前端面试技巧与实践
  • 基于AWS云平台的法律AI应用系统开发方案
  • 嵌入式软件、系统、RTOS(高软23)
  • 十年磨一剑!上海科学家首次揭示宿主识别肠道菌群调控免疫新机制
  • 颜福庆与顾临的争论:1930年代在中国维持一家医学院要花多少钱
  • 习近平出席中拉论坛第四届部长级会议开幕式并发表主旨讲话
  • 极限拉扯上任巴西,安切洛蒂开启夏窗主帅大挪移?
  • 飙升至熔断,巴基斯坦股市两大股指收盘涨逾9%
  • 香港将展“天方奇毯”,从地毯珍品看伊斯兰艺术