一,问题描述
给定一个已排序的正整数数组nums,和一个正整数n。从[1, n]区间内选取任意个数字 补 充 到 nums 中 , 使 得 [1,n] 区 间 内 的 任 何 数 字 都 可 以 用 nums 中 某 几 个 数 字 的 和 来 表 示。请输出满足上述要求的最少需要补充的数字个数。
实例1:
输入: n u m s=[ 1 , 3 ] , n=6
输出: 1
解释: 根据n u m s里现有的组合[ 1 ] , [ 3 ] , [ 1 , 3 ],可以得出1 , 3 , 4。 现 在 如 果 我 们 将 2 添 加 到 n u m s 中 , 组 合 变 为 : [ 1 ] , [ 2 ] , [ 3 ] , [ 1 , 3 ] , [ 2 , 3 ] , [ 1 , 2 , 3 ]。 其和可以表示数字1 , 2 , 3 , 4 , 5 , 6,能够覆盖[ 1 , 6 ]区间里所有的数。 所以我们最少需要添加一个数字。
实例2:
输入: n u m s=[ 1 , 5 , 1 0 ] , n=2 0
输出: 2
解释:我们需要添加[ 2 , 4 ]。
实例3:
输入: n u m s=[ 1 , 2 , 2 ] , n=5
输出: 0
二,贪心算法解决
由题可知,数组nums是升序序列。
假设数组前k 个数组成的数字范围为[ 1,m],那么加上第k+1 个数 即nums[k]( 数 组 的 下 标 是 从 0 开 始 的 ) 后,这个数字范围就变成:[1,total]U[nums [k],total+nums [k]],一个并集,观察一下我们会发现:
1,如果total+1<nums[k],则中间会有一个空缺,无法变为[1,total+nums[k]].
例如:[1,5]U[7,10],因为5<7-1,所以是没法构成[1,10]的。
此时,我们就要循环添加数字total+1来扩大前面的数字范围,构成更大的范围[1,total*2+1],且直到空缺被填补。
2,如果total+1>=nums[k],则无需再添加数字了。
代码:
int mend(vector<int>& nums, int n)
{
//total 是前k个数的总和,count累计添加的数,k 为数组下标
long total = 0;
int count=0,k=0;
while (total < n)
{
if (k<nums.size() && total + 1 < nums[k])
{
//如果数组能组成的数字范围是[1,total],那么加上nums[k]
//结果就是[1,total+nums[k]]
total += nums[k++];
}
else
{
//添加一个数,count加一
total = total + (total + 1);
count++;
}
}
return count;
}