按要求补全数组

上题

给定一个已排序的正整数数组 nums,和一个正整数 n 。从 [1, n] 区间内选取任意个数字补充到 nums 中,使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示。请输出满足上述要求的最少需要补充的数字个数。

示例 1:

输入: nums = [1,3], n = 6 输出: 1 解释: 根据 nums 里现有的组合 [1], [3], [1,3],可以得出
1, 3, 4。 现在如果我们将 2 添加到 nums 中, 组合变为: [1], [2], [3], [1,3], [2,3],
[1,2,3]。 其和可以表示数字 1, 2, 3, 4, 5, 6,能够覆盖 [1, 6] 区间里所有的数。
所以我们最少需要添加一个数字。 示例 2:

输入: nums = [1,5,10], n = 20 输出: 2 解释: 我们需要添加 [2, 4]。 示例 3:

输入: nums = [1,2,2], n = 5 输出: 0

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/patching-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

int minPatches(int* nums, int numsSize, int n){
    int result=0;
    long mar=1;
    int i=0;
    while(mar<=n)
    {
       if(i<numsSize&&mar>=nums[i])
       {
           mar+=nums[i];
           i++;
       }
       else
       {mar+=mar;
        result++;}
    }
    return result;
}

执行结果:
通过
显示详情
执行用时 :
4 ms
, 在所有 c 提交中击败了
100.00%
的用户
内存消耗 :
7.4 MB
, 在所有 c 提交中击败了
25.00%
的用户

直觉

对于任何缺少的数字,如果我们想要让和能覆盖到它,我们必须添加至少一个小于或等于该数字的数字。否则,将无法覆盖到。想想象你要给一个人 xx
分钱的零钱,但你没有足够的硬币。你肯定会需要面额小于或者等于 xx 的硬币。

算法

假设 miss 是缺少的数字中最小的,则区间 [1, miss) (左闭右开) 已经被完全覆盖。为了覆盖 miss,我们需要添加某些小于等于
miss 的数字。否则将不可能覆盖到。

例如,数组 nums = [1,2,3,8], n = 16。已经覆盖到的数字有区间 [1, 6] 和 [8, 14]。换而言之,7,
15, 16 没有覆盖到。如果你加的数字大于 7,则 7 依然覆盖不到。

假设我们添加的数字是 xx,则区间 [1, miss) 和 [x, x + miss) 均被覆盖到。由于我们知道 x <=
miss,这两个区间必然覆盖了区间 [1, x + miss)。我们希望能够尽可能选择大的
xx,这样覆盖的范围就可以尽可能大。因此,最好的选择是 x = miss。

在覆盖到 miss 后,我们可以重新计算覆盖范围,查看新的最小的缺少数字。然后加上该数字。重复操作直到全部数字都被堵盖到。

下面是这个贪心算法的流程:

  1. 初始化区间 [1, miss) = [1, 1) = 空
  2. 每当 n 没有被覆盖
    • 若当前元素 nums[i] 小于等于 miss 将范围扩展到 [1, miss + nums[i]) 将 i 增加 1
    • 否则 将 miss 添加到数组,将范围扩展到 [1, miss + miss) 增加数字的计数
  3. 返回增加数字的数目

作者:LeetCode
链接:https://leetcode-cn.com/problems/patching-array/solution/an-yao-qiu-bu-qi-shu-zu-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这是领扣的官方解答,还有详细的例子和原理

发布了37 篇原创文章 · 获赞 1 · 访问量 664

猜你喜欢

转载自blog.csdn.net/zzuzhaohp/article/details/103318847