leetcode刷题打卡 ---- 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

解题思路:【数学思想+贪心算法】

以 示例2 为例:

假设 nums 为空,求覆盖[1,20]的最小元素之和,
可以从最小的1开始逐个分析,因为nums已经假设为空,因此1必须加入;
然后再分析2,此时 nums 中只有一个1,可以加入1也可以加入2,此时出于贪心考虑,将2加入nums(如果加入1,则最多只能表示到2,但是如果加入2,则可以表示1,2,3=1+2);
再分析3,由于 nums 中1+2=3可以表示3,所以pass;
再分析4,nums 目前最大的数为1+2=3,所以加入4(加入4而不是1,2,3的原因同2);
......
以此类推,最后得到 nums 如下:
[1,2,4,8,16]

其中明确几个要点:
1、贪心思想,每次加入nums的数都要在满足条件的前提下尽可能的大以覆盖更大的范围。
2、因为是从小到大分析,因此每次有数加入 nums 一定是因为 nums 的总和小于这个数从而无法表示。
3、如果当前分析到k,则[1,k]一定可以全部由nums中的某些数之和表示。

数学分析:

由上述分析得出的 nums[1,2,4,8,16] 可得出规律公式:nums[i] = 2^(i-1)  (这里的i是从1开始,而不是从0开始)

以[1,2]为例,分析到4时发现nums总和为3,不足以表示4,因此将4加入nums,

但同时也说明nums可以表示[1,3]的任何数(1,2,1+2=3),加入4后则能够表示的数变为[1-7]的任何数,其中 5 和 7 由[1,3]分别加上新加入的4得到。

同样,[1,2,4,8]能表示[1-15] 【15=1+2+4+8】的所有数字,表示方法如图:
在这里插入图片描述

问题的关键在于 如何用最少的数字相加构成 [1,n) 的所有数

1,2 -> [1,4)

1,2,4 -> [1,8)

1,2,4,8 -> [1,16]

1,2,4,8,16 -> [1,32)

因此当输入 nums 为空时,只需要分别查看 2^i 是否存在即可。
显然,如果输入 nums 为空,则 ⌊log2(n)⌋+1 即为答案。

进一步分析:

那如果nums不为空,回到示例2,假设nums为[8],当计算到8时发现nums已经包含8,因此这一步不需要记入需要补齐的数字个数并计算下一个数16。

假设nums为[5],则在4以及之前的计算不受影响,但是计算到8时发现nums中包含数字5,根据分析结果,此时nums为[1,2,4,5],如果忽略5,仅看[1,2,4],显然可以表示[1,7],当加入5后,则nums可以表示的范围增加[1,7] => [6,12];即nums可以表示[1,12]的范围,下一个缺失的数是13=5+7+1=5+8,即如果不存在5,则下一个缺失的数应该是8,但是由于5的存在使得nums查看到5的时候下一个缺失的数增加了5(5提供了额外的[8,12]这个nums能够表示的范围),因此下一个缺失的数为8+5=13;当查找下一个缺失的数时,根据之前的分析可以得知加入13前nums可以表示[1,12],而加入13后则可以表示[1,12+13=25],因此下一个缺失的数为26=12+13+1。

假设nums为[5,10],则在5之后,下一个缺失的数为13,但是发现nums中包含数字10,与上文类似的思路,由于10的存在似的nums的表示范围从[1,12]扩展到[1,22],因此下一个缺失的数是23。

代码分析:
明确了上述思路,代码其实十分简单只需要根据当前缺失的数curr 和 nums 中 是否有比 curr 小且未使用过的数确定下一个缺失的数curr 即可。
根据分析,当计算到curr时,[1,curr-1]已经能够被nums所表示,因此只需要记录当前缺失的数,即可保证之前所有的数全部可以表示。

class Solution {
    public int minPatches(int[] nums, int n) {
		int count = 0, index = 0;
		long curr = 1;
		while (curr <= n) {
			if (index >= nums.length || nums[index] > curr) {
				count++;
				curr *= 2;
			} else {
				curr += nums[index++];
			}
		}
		return count;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值