330. Patching Array(Hard)

来源:互联网 发布:c语言怎么实现多线程 编辑:程序博客网 时间:2024/06/06 23:18

原题目:
  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:nums = [1, 3], n = 6Return 1.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:nums = [1, 5, 10], n = 20Return 2.The two patches can be [2, 4].Example 3:nums = [1, 2, 2], n = 5Return 0.

题目大意如下:
  给定一个从小到大排好序正整数数组nums和一个整数n,要求在这些数组中补充一些元素,使得[1,n]这个区间的所有数都能由数组中的部分元素求和得到。返回需要添加的最少的元素个数。

解题思路:
  这个问题问的是“the minimum number of patches required”也就是要求出一个最优解,一般涉及到最优解的问题都可以用动态规划或者贪心算法解决,这里我们可以先用贪心算法。那理所当然的下一步,就是寻找最优子结构——子问题的最优解。
  举个例子,nums=[1,2,3,9],既然这个数组已经是排好序的,很自然我们会想到从左到右遍历这个数组看看我们会有什么发现。
  遇到nums[0] = 1,那么[1]这个区间的所有数可以得到;
  遇到nums[1] = 2,那么[1,2,3]这个区间的所有数可以得到;
  遇到nums[2] = 3,那么[1,2,3,4,5,6]这个区间的所有数可以得到;
  遇到nums[4] = 9,那我们只能得到[1,2,3,4,5,6 , 9,10…15]这个区间内的所有数,显然我们需要7和8。
  要得到7,我们可以从[1,2,3,4,5,6,7]当中任意挑选一个数,那哪个是最优选择呢?显然,最能让我们快速到达结果的那个就是最优,即最大的那个数——7(也是原来区间当中最大的数加一)。当我们选择7之后(从遇到nums[2]往后遍历),我们可以得到[1…13]这个区间里的所有数。最后遇到nums[4] = 9我们 [1…21]这个区间里的所有数。
  最后,当区间里最大的数小于n时,重复按照以上标准添加元素即可。
  
注意:
  对于区间的扩展,如果我们可以得到1到n的所有数,当我们拿进来n+1,那我们可以得到1到n+(n+1)所有数。例如,[1,2,3,4,5,6],如果我们有7则可以得到[1,2,3,4,5,6,7,8,9,10,11,12,13]——把7对应每个元素相加即可。
  
代码如下:

class Solution {public:    int minPatches(vector<int>& nums, int n) {        //sum到最后数字可能会变得特别大        long sum = 0 , ans = 0 ;        //如果区间为空,一直添加最大值加一        if(nums.empty()){            while(sum < n){                sum += sum +1 ;                ans++ ;            }            return ans ;        }        for(int i = 0 ; i < nums.size() ; ++i){            while(nums[i] > sum + 1){                sum += sum +1 ;                ans++ ;                //每次添加后判断是否满足,避免多余添加                if(sum >= n) return ans ;            }            sum += nums[i] ;            if(sum >= n) return ans ;        }        //如果原来的区间遍历完以后还没有大于n        while(sum < n){            sum += sum +1 ;            ans++ ;        }        return ans ;    }};

运行结果:
运行结果

算法分析:
  最主要的是便利整个数组,所以为O(n)。

0 0
原创粉丝点击