首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >2025-12-06:硬币面值还原。用go语言,给出一个从 1 开始索引的整数数组 numWays,其中 numWays[i]

2025-12-06:硬币面值还原。用go语言,给出一个从 1 开始索引的整数数组 numWays,其中 numWays[i]

作者头像
福大大架构师每日一题
发布2025-12-19 09:37:35
发布2025-12-19 09:37:35
340
举报

2025-12-06:硬币面值还原。用go语言,给出一个从 1 开始索引的整数数组 numWays,其中 numWays[i] 表示用若干种固定面额且每种可重复使用的硬币,凑出金额 i 的方案数。所有面额都是正整数,且最大不会超过 numWays 的长度。目前具体的面额信息丢失了,你需要推断出可能导致该 numWays 的硬币面额集合。

输出应为一个按升序排列的不重复面额列表(即所有可能出现的面额);如果不存在任何能生成该 numWays 的面额组合,则返回空数组。

输入: numWays = [0,1,0,2,0,3,0,4,0,5]。

输出: [2,4,6]。

解释:

金额

方法数

解释

1

0

无法用硬币凑出总金额 1。

2

1

唯一的方法是 [2]。

3

0

无法用硬币凑出总金额 3。

4

2

可以用 [2, 2] 或 [4]。

5

0

无法用硬币凑出总金额 5。

6

3

可以用 [2, 2, 2]、[2, 4] 或 [6]。

7

0

无法用硬币凑出总金额 7。

8

4

可以用 [2, 2, 2, 2]、[2, 2, 4]、[2, 6] 或 [4, 4]。

9

0

无法用硬币凑出总金额 9。

10

5

可以用 [2, 2, 2, 2, 2]、[2, 2, 2, 4]、[2, 4, 4]、[2, 2, 6] 或 [4, 6]。

题目来自力扣3592。

🔍 问题解决步骤详解

  1. 1. 初始化动态规划数组
    • • 创建一个长度为 n+1 的数组 f(其中 nnumWays 的长度),用于记录使用当前已推断出的硬币面额组合,凑出金额 0n 的方案数。
    • • 将 f[0] 初始化为 1,表示凑出金额 0 的方案数为 1(即不取任何硬币)。对于 i1nf[i] 的初始值均为 0
  2. 2. 遍历每个金额并检查方案数
    • • 从金额 i = 1 开始遍历至 i = n(对应 numWays 的索引为 i-1):
      • • 获取 numWays[i-1] 的值,即题目给定的凑出金额 i 的方案数,记为 ways
      • • 比较 ways 与当前动态规划数组计算出的方案数 f[i]
        • 情况一:ways == f[i]
          • • 说明当前已推断出的硬币面额组合已经能正确生成金额 i 的方案数,无需添加新的面额。直接继续处理下一个金额 i+1
        • 情况二:ways != f[i]
          • • 此时需要尝试添加新的面额以匹配给定的方案数。检查条件 ways - 1 == f[i] 是否成立:
          • • 如果成立,则表示可以通过添加一个面额为 i 的硬币来弥补方案数的差距。将面额 i 加入结果集 ans,并执行下一步的完全背包更新。
          • • 如果不成立,则说明无法通过添加面额 i 来满足给定的方案数,立即返回空数组 nil,表示不存在可行的硬币面额组合。
  3. 3. 更新动态规划数组(完全背包更新)
    • • 当添加了新的面额 i 后,需要更新动态规划数组 f 以反映新面额对后续金额方案数的影响。这个过程类似于解决完全背包问题。
    • • 具体操作是:对于金额 jin(从小到大),执行 f[j] += f[j - i]。这表示,对于每个金额 j,新增的方案数等于使用新面额 i 后,凑出金额 j-i 的方案数(因为加上一个面额 i 的硬币即可凑出金额 j)。 通过这样的更新,f 数组能动态地记录当前所有已选面额组合下的方案数。
  4. 4. 输出结果
    • • 如果成功遍历完所有金额 1n 且没有返回空数组,则收集到的结果集 ans 就是按升序排列的可能硬币面额集合(因为 i 是递增遍历的)。

⏱ 复杂度分析

  • 时间复杂度O(n^2)
    • • 需要遍历每个金额 i(从 1n),共 n 次循环。
    • • 在最坏情况下,每次循环都可能需要更新动态规划数组(内层循环从 in),内层循环的次数平均约为 n/2
    • • 因此,总体时间复杂度为平方级别 O(n^2)
  • 空间复杂度O(n)
    • • 主要空间开销来自动态规划数组 f,其大小为 n+1,因此额外空间复杂度为线性 O(n)

💎 核心思路总结

这个算法的核心在于贪心策略和动态规划的结合。它从小到大依次考虑每个金额,通过对比给定方案数与当前计算方案数的差异,动态地推断出必须存在的硬币面额,并利用完全背包的思想更新方案数。其正确性依赖于硬币面额是正整数且不超过 n 的条件,从而保证了解的唯一性(如果存在)。

Go完整代码如下:

代码语言:javascript
复制
package main

import (
    "fmt"
)

func findCoins(numWays []int) (ans []int) {
    n := len(numWays)
    f := make([]int, n+1)
    f[0] = 1
    for i := 1; i <= n; i++ {
        ways := numWays[i-1]
        if ways == f[i] {
            continue
        }
        if ways-1 != f[i] {
            returnnil
        }
        ans = append(ans, i)
        // 现在得到了一个大小为 i 的物品,用 i 计算完全背包
        for j := i; j <= n; j++ {
            f[j] += f[j-i]
        }
    }
    return
}

func main() {
    numWays := []int{0, 1, 0, 2, 0, 3, 0, 4, 0, 5}
    result := findCoins(numWays)
    fmt.Println(result)
}

Python完整代码如下:

代码语言:javascript
复制
# -*-coding:utf-8-*-

from typing importList

deffindCoins(numWays: List[int]) -> List[int]:
    n = len(numWays)
    f = [0] * (n + 1)
    f[0] = 1
    ans = []
    
    for i inrange(1, n + 1):
        ways = numWays[i - 1]
        if ways == f[i]:
            continue
        if ways - 1 != f[i]:
            returnNone
        ans.append(i)
        # 现在得到了一个大小为 i 的物品,用 i 计算完全背包
        for j inrange(i, n + 1):
            f[j] += f[j - i]
    
    return ans

defmain():
    numWays = [0, 1, 0, 2, 0, 3, 0, 4, 0, 5]
    result = findCoins(numWays)
    print(result)

if __name__ == "__main__":
    main()

C++完整代码如下:

代码语言:javascript
复制
#include <iostream>
#include <vector>
usingnamespace std;

vector<int> findCoins(const vector<int>& numWays) {
    int n = numWays.size();
    vector<int> f(n + 1, 0);
    vector<int> ans;

    f[0] = 1;
    for (int i = 1; i <= n; i++) {
        int ways = numWays[i - 1];
        if (ways == f[i]) {
            continue;
        }
        if (ways - 1 != f[i]) {
            return {};  // 返回空vector
        }
        ans.push_back(i);
        // 现在得到了一个大小为 i 的物品,用 i 计算完全背包
        for (int j = i; j <= n; j++) {
            f[j] += f[j - i];
        }
    }
    return ans;
}

int main() {
    vector<int> numWays = {0, 1, 0, 2, 0, 3, 0, 4, 0, 5};
    vector<int> result = findCoins(numWays);

    // 输出结果
    cout << "[";
    for (size_t i = 0; i < result.size(); i++) {
        cout << result[i];
        if (i != result.size() - 1) {
            cout << ", ";
        }
    }
    cout << "]" << endl;

    return0;
}

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 福大大架构师每日一题 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🔍 问题解决步骤详解
  • ⏱ 复杂度分析
  • 💎 核心思路总结
  • Go完整代码如下:
  • Python完整代码如下:
  • C++完整代码如下:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档