Google 面试题:数组补丁

Question

给出一个从小到大排好序的整数数组 nums 和一个整数 n,在数组中添加若干个补丁(元素)使得 [1,n] 的区间内的所有数都可以表示成 nums 中若干个数的和。返回最少需要添加的补丁个数。

Example1:

nums = [1, 3], n = 6
返回1,表示至少需要添加1个数{2},才可以表示1到6之间所有数。

Example2:

nums = [1, 5, 10], n = 20
返回2,表示至少需要添加两个数{2,4},才可以表示1到20之间所有数。

Answer

Solution 1:

使用贪心的思想。

  • 可以考虑相似的简单问题:如果nums数组为空,那么最少需要多少个数字才能表示1到n之间所有数?贪心算法,即按照1、2、4、8…都顺序添加,每次加入都数都比之前所有数的总和大1,直到总和大于n;
  • 对于本题,则是预先在数组中给出了一些数,但贪心策略实质是相同的:假设nums当前至多可以表示1到m之间的所有数,加入m+1,则数组可以表示从1到2m+1的任意的数,令新的m=2m+1;直到m大于等于n,则数组可以表示从1到n的所有数。
class Solution {
    public int minPatches(int[] nums, int n) {
        long sum = 0;
        int ans = 0;    //用于记录需要添加数字的个数
        int index = 0;  // 用于记录数组遍历的位置
        if (nums.length > 0 && nums[0] == 1) {
            sum = 1;
            index = 1;
        }
        while (sum < n)
        {
            // 判断数值中的下一个元素是否大于当前和,即为m+1,不满足则不用在该位置添加新元素
            while (index < nums.length && nums[index] <= sum) 
            {
                sum += nums[index];
                index++;
            }

            // 满足m+1的条件,则先判断原数组中是否存在m+1的元素,不存在则添加新元素
            if (sum < n) {
                if (index < nums.length && nums[index] == sum + 1) 
                    index++;
                else {
                    ans++;
                }
                sum = 2 * sum + 1;
            }
        }
        return ans;
    }
}
  • 时间复杂度:O(n);空间复杂度:O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值