leetcode 330. 按要求补齐数组

330. 按要求补齐数组
给定一个已排序的正整数数组 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


这道题的精髓在于贪心,原始的数列中可以组成多个可得到的区间,但是这些区间不一定包含我们需要的 n 值,或者这些区间是分开的,区间与区间之间有一些空的不能到达的数。本题的核心就是依次填充这个较小miss数。

在这里miss数的更新方式有两种:

  1. 加入miss数与之后列表内要添加的数 val 相比,miss数比较大,那么在[1, miss)这个区间内,已经可以包含val了,我们增加val之后,只是将我们的可获得数的右边界增加到[ 1, miss+val )。
  2. 第二种情况就是加入的列表内的数的值是大于miss数的,这就意味着,原来[ 1, miss)区间的值是小于val的,我们这里只能从外部新加入一个miss值,扩展可行区间,加入miss值之后,我们的可行区间倍增,变为[ 1, miss+miss)。

这里我们的循环条件是只要miss值小于等于 n就一直循环。右边界方案一的条件是,待加入的序列索引小于等于列表长度,待加入的值小于miss值,这时候 miss = miss + val。
而当列表内的值取完了的时候,或者列表的值大于当前的miss值时候,我们需要添加一个miss值,导致右边界变成 miss + miss。

class Solution:
    def minPatches(self, nums: List[int], n: int) -> int:
        count = 0
        miss = 1
        idx = 0
        while miss <= n:
            if idx < len(nums) and nums[idx] <= miss:#如果数组内的下一个数小于miss数
                miss += nums[idx]#miss数则等于之前的miss边界加新加入的数
                idx += 1#由于添加了列表内的数,所以右移
            else:#如果miss数值不能由之前的产生,怎添加这个miss数,覆盖范围倍增,miss数变成原来的两倍
                count += 1
                miss += miss#missb倍增
        return count

猜你喜欢

转载自blog.csdn.net/qq_38650028/article/details/107494102