如何利用AI刷题基础篇4——高效刷题|豆包MarsCode AI刷题

83 阅读2分钟

本文专注于记录我如何使用AI完成算法刷题练习,以此来分享如何高效利用AI刷题。


#123最优硬币组合问题

问题描述

现在有 M 种不同面值的硬币(硬币个数数目无限),如何用这些硬币组合为总数额为 N 的钱,同时满足使用硬币的个数最少?

输入格式

第一行为硬币面值正整数数组 (无序)

第二行为目标总数额,正整数

输出格式

总面值等于目标总数额的,且长度最小的硬币组合数组,结果不要求排序。如果不存在解则返回空数组

输入样例

[1,2,5]
18

输出样例

[5,5,5,2,1]

思路

这是一个典型的最小硬币数问题,可以采用动态规划来处理。我们依旧是明确输入,输出和处理。

输入

  1. 硬币面值数组:一个包含不同面值硬币的数组,每个面值都是正整数。例如 [1, 2, 5]
  2. 目标总金额:一个正整数,表示需要用硬币组合成的总金额。例如 18

输出

  1. 硬币组合数组:一个数组,表示组成目标总金额所需的最少硬币组合。如果无法组成目标总金额,则返回空数组 []。例如 [5, 5, 5, 2, 1]

处理

设计一个算法能计算出所需最少硬币数,并且返回长度最小的硬币组合数组。

算法设计

采用动态规划来解决,核心思想是逐步计算出每个金额(从 0 到目标金额 N)可以用的最少硬币数,并存储对应的硬币组合。那么状态的定义和状态转移方程是一定要明确的。

  • dp[i] :

    • 表示组成金额 i 所需的最少硬币数量。
    • 初始化为 INT_MAX,表示默认不可达。
    • 特例:dp[0] = 0,因为金额为 0 时不需要任何硬币。
  • 状态转移方程:dp[i] = min(dp[i], dp[i - coin] + 1)


代码实现

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

vector<int> solution(vector<int> coins, int amount) {
    // dp[i] 表示组成金额 i 的最少硬币数
    vector<int> dp(amount + 1, INT_MAX);
    // last_coin[i] 用来追溯最小硬币组合
    vector<int> last_coin(amount + 1, -1);

    // base case, dp[0] = 0,0金额需要0个硬币
    dp[0] = 0;

    // 动态规划过程
    for (int coin : coins) {
        for (int i = coin; i <= amount; ++i) {
            if (dp[i - coin] != INT_MAX && dp[i] > dp[i - coin] + 1) {
                dp[i] = dp[i - coin] + 1;
                last_coin[i] = coin;
            }
        }
    }

    // 如果 dp[amount] 仍然是 INT_MAX,说明无法组成 amount
    if (dp[amount] == INT_MAX) {
        return {};
    }

    // 通过 last_coin 数组恢复硬币组合
    vector<int> result;
    int current_amount = amount;
    while (current_amount > 0) {
        int coin = last_coin[current_amount];
        result.push_back(coin);
        current_amount -= coin;
    }

    return result;
}

int main() {
    // 测试用例
    vector<int> result = solution({1, 2, 5}, 18);
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl; // 输出 5 5 5 2 1(顺序不固定)

    return 0;
}