leetCode330:按要求補齊陣列
阿新 • • 發佈:2021-01-11
技術標籤:刷題筆記
目錄
一、題目描述
給定一個已排序的正整數陣列 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} =>[1, 1
- 用nums[1, 2, 5], n = 20;來舉例:
- nums[1, 2, 5], n = 20;
- 首先初始狀態的覆蓋範圍為0,看第一個元素1,初始狀態加上1之後的覆蓋範圍變為[1, 1](此時我們希望接下來要新增的數字為2,因為需要保證覆蓋範圍可以用和的形式表示的連續性,且增加的數最少)
- 看第二個元素為2(等於我們的預期,不用額外增加數字),第2步中的覆蓋範圍加上2得到新的覆蓋範圍[1, 3](此時我們希望接下來要新增的數字為4);
- 看第三個元素為5(大於我們的預期),此時如果不增加額外的數字直接擴充套件範圍會得到[1,8]的範圍,但是不符合和表示的連續性,因為數字4不能使用和的形式來表示;所以我們需要新增額外的數字4,第2步中的覆蓋範圍加上4得到新的覆蓋範圍[1,7](接下來我們希望要新增的數字時8);
- 再看第三個元素5(小於我們的預期,不增加額外的數字),在第4步中的覆蓋範圍中加上5得到[1, 12](此時我們希望接下來新增的數字是13);
- 陣列中已經沒有元素,但是我們的覆蓋範圍還達不到要求,所以還需要新增數字13,在第5步中的範圍中加上13得到[1,25](此時我們希望接下來新增的數字時26);
- 陣列中已經沒有元素,且覆蓋範圍達到要求,過程中一共新增了2個數字,4和13。返回結果為2。
在實現時,我們初始希望新增的數字是1(初始的覆蓋範圍為[0, 0]),要注意這個細節。
三、程式碼實現
#include <bits/stdc++.h>
using namespace std;
int minPatches(vector<int>& nums, int n) {
int length = nums.size();
//用來記錄目前所能覆蓋的範圍,注意表示的範圍是[1, curr - 1];
//初始範圍為[1,0]
long long int curr = 1;
//res為結果值,index為當前遍歷的下標值
int res = 0, index = 0;
while (curr <= n) {
//陣列沒有完並且陣列當前值不大於curr值
//表示當前最小的未被覆蓋的值是nums[index]
if (index < length && nums[index] <= curr) {
curr += nums[index];
index++;
} else {
//否則表示覆蓋不具有連續性,需要先覆蓋到curr-1後面的值curr
//覆蓋curr-1後面的數且滿足新增的數最少,即新增一個curr
curr <<= 1;
//新增一次,結果+1
res++;
}
}
return res;
}
int main() {
vector<int> nums = { 1,5,10 };
cout << minPatches(nums, 20) << " ";
return 0;
}