【Leetcode】2952. 需要添加的硬币的最小数量

文章讲述了如何使用贪心算法解决给定硬币面值数组中找到最少额外硬币数,以确保数组的子序列可以覆盖从1到目标金额的所有整数。算法通过先排序硬币,然后逐步添加大面值硬币来达到目标。
摘要由CSDN通过智能技术生成

题目

题目链接🔗
给你一个下标从 0 0 0 开始的整数数组 c o i n s coins coins,表示可用的硬币的面值,以及一个整数 t a r g e t target target

如果存在某个 c o i n s coins coins 的子序列总和为 x x x,那么整数 x x x 就是一个 可取得的金额

返回需要添加到数组中的 任意面值 硬币的 最小数量 ,使范围 [ 1 , t a r g e t ] [1, target] [1,target] 内的每个整数都属于 可取得的金额

数组的 子序列 是通过删除原始数组的一些(可能不删除)元素而形成的新的 非空 数组,删除过程不会改变剩余元素的相对位置。

示例 1
输入:coins = [1,4,10], target = 19
输出:2
解释:需要添加面值为 2 2 2 8 8 8 的硬币各一枚,得到硬币数组 [ 1 , 2 , 4 , 8 , 10 ] [1,2,4,8,10] [1,2,4,8,10]
可以证明从 1 1 1 19 19 19 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 2 2 2

示例 2
输入:coins = [1,4,10,5,7,19], target = 19
输出:1
解释:只需要添加一枚面值为 2 2 2 的硬币,得到硬币数组 [ 1 , 2 , 4 , 5 , 7 , 10 , 19 ] [1,2,4,5,7,10,19] [1,2,4,5,7,10,19]
可以证明从 1 1 1 19 19 19 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 1 1 1

示例 3
输入:coins = [1,1,1], target = 20
输出:3
解释
需要添加面值为 4 4 4 8 8 8 16 16 16 的硬币各一枚,得到硬币数组 [ 1 , 1 , 1 , 4 , 8 , 16 ] [1,1,1,4,8,16] [1,1,1,4,8,16]
可以证明从 1 1 1 20 20 20 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 3 3 3

提示

  • 1 ≤ t a r g e t ≤ 1 0 5 1 \leq target \leq 10^5 1target105
  • 1 ≤ c o i n s . l e n g t h ≤ 1 0 5 1 \leq coins.length \leq 10^5 1coins.length105
  • 1 ≤ c o i n s [ i ] ≤ t a r g e t 1 \leq coins[i] \leq target 1coins[i]target

思路

可以通过贪心算法来解决。我们首先对硬币面值数组进行排序,然后逐步考虑每个需要添加的额外硬币。具体步骤如下:

  1. 对硬币数组进行排序,以便从小到大考虑硬币面值。
  2. 初始化需要的额外硬币数量为0,当前已经能够组成的金额为0。
  3. 遍历排序后的硬币数组,对于每个硬币面值,进行以下操作:
  • 如果当前已经能够组成的金额已经大于或等于目标金额,直接返回需要的额外硬币数量。
  • 如果当前硬币面值减去1大于当前已经能够组成的金额,需要添加额外硬币,数量为当前硬币面值减去1与当前已经能够组成的金额之间的差值。
  • 更新当前已经能够组成的金额为当前硬币面值。
  1. 如果遍历完成后,当前已经能够组成的金额仍然小于目标金额,继续添加额外硬币,数量为目标金额减去当前已经能够组成的金额。

代码

class Solution {
public:
    int minimumAddedCoins(vector<int>& coins, int target) {
        int n = coins.size(), res = 0, ssum = 0;
        sort(coins.begin(), coins.end());
        for (int i = 0; i < n; ++i) {
            if (ssum >= target) {
                return res;
            }
            while (ssum < coins[i] - 1) {
                ++res;
                ssum = ssum * 2 + 1;
            }
            ssum += coins[i];
        }
        while (ssum < target) {
            ++res;
            ssum = ssum * 2 + 1;
        }
        return res; 
    }
};
/*
挺有意思的一个构造题。

不难看出,当你已经可以组成1 -- i所有的数字的时候,,如果下一个出现的数字j小于等于i + 1,那么你就可以直接获得这个数字,并且能通过这个新的数字来组成1 -- i + j的所有数字。这是很好理解的一件事儿,1 -- i的所有数字你本来就有,j -- i + j的所有数字则可以通过你原本能组成的数字再加上j来获取。

那么,如果下一个出现的数字j大于i + 1,这时就需要额外添加数字了。额外添加的数字自然是越大越好——也就是前一种情况里j的最大值i + 1。
*/

复杂度分析

时间复杂度

O(nlogn),遍历硬币数组的时间复杂度为 O(n),因此总的时间复杂度为 O(nlogn)。

空间复杂度

O(1)

结果

在这里插入图片描述

总结

通过贪心算法解决了硬币补充的问题,通过分析问题的特点,找到了最优的添加策略,使得所需的额外硬币数量最小化。

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要AC的dly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值