LeetCode330. 按要求补齐数组
给定一个已排序的正整数数组 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
提示:
1 <= nums.length <= 1000nums按 升序排列
思路分析
本题的贪心思想即来源于此,为了使补充的新数物尽其用,能够直接扩大可表示的区间范围,把补充的num设为ach + 1即可。此时能表示的数字区间可以直接更新为[1, ach + ach + 1],不会漏掉中间的数字。
假设数组 arr 添加一个元素即可覆盖 [1,n) 内所有数字,那么添加的数字 m 一定满足m <= n; 假设数组 arrarrarr 可以覆盖 [1,n) 的所有数字,则给 arr 内加元素 m 若m <= n,新数组可以覆盖[1, m + n) = [1, n) ∪ [m, m + n)内所有数字
设置一个初始范围 [1,1),通过不断确认并扩大数组可以覆盖的范围,最终计算出最少需要加入的数字。
- 当i < len(nums)且nums[i] <= add时:不需要加入新数字,循环确认并更新数组可以覆盖的范围[1, add + nums[i]),直到找到大于确认范围 add 的 nums[i] 或索引越界。
- 否则:无法根据现有数字构建更大的连续范围,,因此需要使用贪心策略向数组加入数字 add ,将数组从覆盖 [1,add) 扩容至可覆盖 [1,2add) 。
- 直到确认的范围add > n,说明此时已经覆盖 [1,n] ,退出迭代并返回。
算法代码
class Solution {
public int minPatches(int[] nums, int n) {
int i = 0, count = 0;
long add = 1;
while (add <= n) {
if (i < nums.length && nums[i] <= add) add += nums[i++];
else {
add += add;
count++;
}
}
return count;
}
}
结果详情
算法复杂度
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN)一起进步,一起成长!