算法初探LeetCode-按要求补齐数组

107 阅读1分钟

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 <= 1000
  • 1<=nums[i]<=1041 <= nums[i] <= 10^4
  • nums 按 升序排列
  • 1<=n<=231 11 <= n <= 2^{31} - 1

思路分析

本题的贪心思想即来源于此,为了使补充的新数物尽其用,能够直接扩大可表示的区间范围,把补充的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;
    }
}

结果详情

Snipaste_2023-06-30_16-18-15.png

算法复杂度

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n)O(n)

掘金(JUEJIN)一起进步,一起成长!