贪心-按要求补齐数组

问题描述 :

给定一个已排序的正整数数组 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

 

输入说明 :

首先输入数组长度m,然后输入m个整数。

最后输入一个正整数 n。

n不超过32位int型的表示范围,即:n<=2147483647。

输出说明 :输出一个整数

输入范例 :

3
1 5 10
20

输出范例 :2

#include <iostream>
#include <vector>

using namespace std;

//使用天秤加砝码的思想:
//如果我有砝码0,能称的重量为0
//再加一个砝码1,能称的重量不到2    1
//再加一个砝码2,能称的重量不到4    1    1+2
//再加一个砝码4,能称的重量不到8    1    2    1+2    4  1+4    1+2+4
//再加一个砝码8,能称的重量不到16(16以内的全都能称出来)
//因为我每次前一步已经完全覆盖[0,n),再加一个n kg的不就能覆盖[0,2n)了吗。
//同时为了加的次数最少我们才这样加,不需要1,2,3,4,5.....每种砝码都有。
//只有这样先做到局部加砝码最少,才能保证到后边n很大时加的砝码最少。
class Solution {
public:
    int minPatches(vector<int>& nums, int n) {
        //需要补充的数字个数
        int res = 0;
        //数字累加之和
        long long sum = 1;//一定要注意:使用long long 避免int 相加越界
        int len = nums.size();
        //访问的数组下标索引
        int i = 0;
// 能连续覆盖的重量还没到n,有两种情况:断码(缺砝码),或者还有砝码没加
        while(sum <= n){
            if(i < len && nums[i] <= sum){
                sum += nums[i];
                i++;
            }
    //上面判断语句可能不好理解,若现有砝码1, 4, 6, n为10,当一次循环后砝码1已计入sum即x,x=2
    //进入下一次循环,1<3,但是nums[1]=4>2,这说明断码了进入else语句

    //然后nums[1]=4就等于4,4的砝码我们刚好有,加进来,现在能称的重量就能覆盖到原来的2倍=8了(不到8)
    //然后nums[2]=6<8,这个不是必需的砝码,加进来,现在能称的重量就能覆盖到8+6=14了(不到14)
            else{
                //我们需要的是重量为x=2的砝码,所以加一个,现在能称的重量就能覆盖到原来的2倍=4了(不到4)
                //加一个现在刚好覆盖不到的重量的砝码,覆盖范围翻倍
                sum *= 2;
                res++;//砝码数量+1
            }
            //所以再加1个重量为2的,我们就可以最大称到13.
        }

        return res;
    }
};

int main()
{
//    首先输入数组长度m,然后输入m个整数。
    int m,n;
    cin >> m;

    vector<int> nums;
    int data;
    for(int i = 0;i < m; i++){
        cin >> data;
        nums.push_back(data);
    }

    cin >> n;
//最后输入一个正整数 n。
//
//n不超过32位int型的表示范围,即:n<=2147483647。
    cout << Solution().minPatches(nums, n);
    return 0;
}

 

posted @ 2022-07-26 10:29  夏天最爱的冰淇淋  阅读(25)  评论(0)    收藏  举报