文章目录
- 题目
- 思路
- 代码
- 复杂度分析
- 时间复杂度
- 空间复杂度
- 结果
- 总结
题目
题目链接🔗
给你一个下标从 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 1≤target≤105
- 1 ≤ c o i n s . l e n g t h ≤ 1 0 5 1 \leq coins.length \leq 10^5 1≤coins.length≤105
- 1 ≤ c o i n s [ i ] ≤ t a r g e t 1 \leq coins[i] \leq target 1≤coins[i]≤target
思路
可以通过贪心算法来解决。我们首先对硬币面值数组进行排序,然后逐步考虑每个需要添加的额外硬币。具体步骤如下:
- 对硬币数组进行排序,以便从小到大考虑硬币面值。
- 初始化需要的额外硬币数量为0,当前已经能够组成的金额为0。
- 遍历排序后的硬币数组,对于每个硬币面值,进行以下操作:
- 如果当前已经能够组成的金额已经大于或等于目标金额,直接返回需要的额外硬币数量。
- 如果当前硬币面值减去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)
结果
总结
通过贪心算法解决了硬币补充的问题,通过分析问题的特点,找到了最优的添加策略,使得所需的额外硬币数量最小化。