Patching Array

给定一个有序正整数数组nums和一个整数n,通过添加数组中的元素,使得数组能表示从1到n的所有整数。返回所需的最小补全次数。题目提供了两个示例解释了补全过程,强调了贪心策略的应用,并指出在遍历过程中不能对集合进行增删操作以避免迭代器问题。解题关键在于使用cur表示当前能表示的范围,并根据贪心原则更新nums。
摘要由CSDN通过智能技术生成

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].

Example 3:
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;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值