330. Patching Array

Given a sorted positive integer array nums and an integer n, add/patch elements to the array such that any number in range [1, n] inclusive can be formed by the sum of some elements in the array. Return the minimum number of patches required.
Example 1:

Input: nums = [1,3], n = 6
Output: 1 
Explanation:
Combinations of nums are [1], [3], [1,3], which form possible sums of: 1, 3, 4.
Now if we add/patch 2 to nums, the combinations are: [1], [2], [3], [1,3], [2,3], [1,2,3].
Possible sums are 1, 2, 3, 4, 5, 6, which now covers the range [1, 6].
So we only need 1 patch.

Example 2:

Input: nums = [1,3], n = 6
Output: 1 
Explanation:
Combinations of nums are [1], [3], [1,3], which form possible sums of: 1, 3, 4.
Now if we add/patch 2 to nums, the combinations are: [1], [2], [3], [1,3], [2,3], [1,2,3].
Possible sums are 1, 2, 3, 4, 5, 6, which now covers the range [1, 6].
So we only need 1 patch.

Example 3:

Input: nums = [1,2,2], n = 5
Output: 0

This is the right greedy solution with C++

int minPatches(vector<int>& nums, int number)
{
    long long cur = 0, count = 0, i = 0;
    while (cur < number)
    {
        if (i < nums.size() && cur + 1 >= nums[i])cur += nums[i++];
        else { cur += (cur + 1); count++; cout << cur << endl; }
    }
    return count;
}

We want to get all numbers in the [1, number] as well as add as less numbers as possible.
The solution we can easily think of is finding all numbers that could be formed by some elements of the vector nums, then add those not included in the range of [1, number] into the vector nums.
Then I get the following solution which just passed six test cased with a Time Limit Exceed, which make feel extremely uncomfortable
I get through from 1 to number with i, and judge whether i belongs to the vector nums. If it does, I just continue, else I used greedy search to find whether i can be formed by nums's some elements. Firstly, by a binary search, i find the right position j that i should be inserted into nums at by ascending order. Then the consequence by judging whether i can be formed by num's some elements with greedy algorithm will decide to adding a new element into nums or do nothing.

//We design a function to find the right position some number should be inserted at by ascending order.
//Binary search should be a great choice.
//And we should be clear there is no possibility number equals any element of nums.
int rightposition(vector<int>& nums, int number)
{
    //The variable n is the size of nums.
    int n = nums.size();
    //We just return result if it's one of the following situations.
    if (n == 0 || number < nums[0])return 0;
    if (number > nums[n - 1])return n;
    int start = 0, end = n, mid = 0;
    while (start < end)
    {
        int mid = (start + end) / 2;
        if (number < nums[mid])end = mid;
        else start = mid + 1;
    }
    return start;
}
int minPatches(vector<int>& nums, int n)
{
    //We put all the elements of nums into the set se so that we can judge whether some number exists in the nums quackly.
    unordered_set<int> se;
    for (int i = 0; i < nums.size(); i++)se.insert(nums[i]);
    int count = 0;
    for (int i = 1; i <= n; i++)
    {
        //Firstly, if i is included by se, then we continue.
        if (se.find(i) != se.end())continue;
        //If i doesn'y belong to se, then we find the right if we want to insert i into nums
        int right = rightposition(nums, i);
        //We use as many element of nums to make up i, which is called greedy algorithm.
        int j = right, number = i;
        while (j >= 0)
        {
            if (number < nums[j]) { j--; continue; }
            number -= nums[j--];
            if (number == 0)break;
        }
        //If number doesn't equal 0, which means we can't use the elements of nums to make up number, then we put number into nums by ascending order.
        if (number != 0)
        {
            se.insert(i);
            nums.insert(nums.begin() + right, i);
            count++;
        }
    }
    return count;
}

Can’t believe it, huh…..
Now, Let make the first solution clear. Supposing we have ensured that any number from 1 to A can be formed by the elements of nums whose index is in the range[0, i], and what number can we get if we use the elements of nums between index 0 and index i + 1. The answer is clearly 1 to A and nums[i + 1]) to (A + nums[i + 1]), which can be combined into (1, A + nums[i + 1]) if A + 1 >= nums[i + 1], in another situation, A + 1 < nums[i + 1], it means we can’t get A + 1 from index 0 to i + 1, and the nums is sorted by ascending order, which is the precondition of the problem, so we must add a new number whose value equals A + 1 to get A + 1. Then we get the following solution which is shown in the front of the blog.

int minPatches(vector<int>& nums, int number)
{
    long long cur = 0, count = 0, i = 0;
    while (cur < number)
    {
        if (i < nums.size() && cur + 1 >= nums[i])cur += nums[i++];
        else { cur += (cur + 1); count++; cout << cur << endl; }
    }
    return count;
}

http://www.sunshangyu.top/

猜你喜欢

转载自blog.csdn.net/qq_34229391/article/details/82286565