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 = 6
Return 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 = 20
Return 2
.
The two patches can be [2, 4]
.
nums =
[1, 2, 2]
,
n =
5
Return 0
.
一开始自己想复杂了,例如[1,5,10],20这个例子。我先用求出用nums能得到的数字,然后把最小的不能得到的数字往集合里加。于是乎,当数字很大的时候都过不了,伤心。做法如下:
这里要注意,Iterator在遍历的时候是不能对集合进行增加删除操作的!
class Node{
int end;
int sum;
public Node(int end,int sum){
this.end=end;
this.sum=sum;
}
}
public class Solution {
public int minPatches(int[] nums, int n) {
int result=0;
Set<Integer> canNotReach=new TreeSet<Integer>();
Set<Integer> canReach=new TreeSet<Integer>();
for(int i=0;i<n;i++)
canNotReach.add(i+1);
List<Node> list=new ArrayList<Node>();
list.add(new Node(-1, 0));
getResult(nums, list, canNotReach, canReach);
while(!canNotReach.isEmpty()){
Set<Integer> copyOfCanNotReach=new TreeSet<Integer>(canNotReach);
Set<Integer> copyOfCanReach=new TreeSet<Integer>(canReach);
Iterator<Integer> canNotReachIterator=copyOfCanNotReach.iterator();
Iterator<Integer> canReachIterator=copyOfCanReach.iterator();
int firstNum=canNotReachIterator.next();
result++;
while(canReachIterator.hasNext()){
int canReachNum=canReachIterator.next();
canNotReach.remove(canReachNum+firstNum);
canReach.add(canReachNum+firstNum);
}
canNotReach.remove(firstNum);
canReach.add(firstNum);
}
return result;
}
public void getResult(int[] nums, List<Node> list, Set<Integer> canNotReach, Set<Integer> canReach){
List<Node> newList=new ArrayList<Node>();
for(int i=0;i<list.size();i++){
for(int j=list.get(i).end+1;j<nums.length;j++){
int val=list.get(i).sum+nums[j];
newList.add(new Node(j, val));
canNotReach.remove(val);
canReach.add(val);
}
}
if(newList.size()==0)
return;
getResult(nums, newList, canNotReach, canReach);
}
}
正确的解法如下:
cur表示当前能表示的范围为[1..cur],扫描nums[ ],贪心原则如下:
若nums[i]<=2*cur + 1,把nums[i]添加进来,表示范围更新[1..cur+nums[i]];
若nums[i]>2*cur + 1,添加新的元素cur+1,表示范围更新[1..2*cur+1].
cur从0开始。
注意,这里可能会溢出,所以应该用long。
public class Solution {
public int minPatches(int[] nums, int n) {
long miss = 1;
int add = 0;
int i = 0;
while (miss <= n) {
if (i < nums.length && nums[i] <= miss){
miss += nums[i++];
} else {
miss += miss;
add += 1;
}
}
return add;
}
}