如何知道我们应该添加最少的数字以获得完整的数组

时间:2016-10-05 19:15:12

标签: java arrays algorithm math

最近我遇到了这样一个问题:
假设你有一个int N,并且你也有一个int [],这个数组中的每个元素只能使用一次。我们需要设计一个算法,通过添加这些数字来获得1到N,最后返回我们需要添加的最少数字 例如:

N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.

我正在考虑使用DFS来解决这个问题。 你有更好的解决方案吗?谢谢!

4 个答案:

答案 0 :(得分:1)

我不知道这是否是一个好的解决方案:

我会创建第二个数组(布尔数组),记住我可以计算的所有数字。 然后我会编写一个模拟向数组添加数字的方法。 (在您的示例中,将1,3和2添加到数组中)。 将更新布尔数组以始终记住可以使用添加的数字计算哪些值(数字)。

在初始数组值上调用add方法之后,如果可以计算x,则测试每个数字x(1 <= x <= N)。如果没有调用x的add方法。

由于我的解释不好,我将添加(未经测试的)Java代码:

static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];

//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){

    //Preperation (adding every given Number in the array)
    for(int i=0; i<arr.length; i++){
        addNumber(arr[i]);
    }

    //The number of elements added to the initial array
    int result = 0;

    //Adding (and counting) the missing numbers (Runtime O(N^2) )
    for(int i=1; i<=N; i++){
        if( !canCalculate[i-1] ){
            addNumber(i);
            result++;
        }
    }
    return result;
}


//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
    System.out.println("Add Number: "+(number));

    boolean[] newarray = new boolean[N];
    newarray[number-1] = true;

    //Test which values can be calculated after adding this number
    //And update the array
    for(int i=1; i<=N; i++){
        if( canCalculate[i-1] ){
            newarray[i-1] = true;
            if( i + number <= N ){
                newarray[i+number-1] = true;
            }
        }
    }
    canCalculate = newarray;
}

编辑:测试代码并更改了一些错误(但rachel的解决方案似乎更好)

答案 1 :(得分:1)

这里解释了为什么OP发布的解决方案有效(简单地说,算法是遍历已排序的现有元素,保留前面现有元素的累积总和并向数组添加元素和总和如果它不存在并超过当前总和):

循环测试每个必须形成的元素,并对前面的元素求和。如果需要的元素大于当前总和,它会提醒我们。如果你仔细想想,它真的很简单!当我们已经使用了所有前面的元素时,我们怎么能制作元素,这就是总和所代表的!

相反,我们怎么知道当和大于当前元素时,所有中间元素都能形成?例如,请考虑n = 7, a = {}

The function adds {1,2,4...} 
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.

At any point, m, in the traversal, we know for sure that 
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm

Therefore, we can make Y-1, Y-2, Y-3...Y-Xm

(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)

Q.E.D.

答案 2 :(得分:0)

这是动态编程中的一个着名问题。您可以在此处参考完整的解决方案https://www.youtube.com/watch?v=s6FhG--P7z0

答案 3 :(得分:0)

我刚刚找到了这样的解决方案

    public static int getNum(int n, int[] a) {
    ArrayList<Integer> output = new ArrayList<Integer>();
    Arrays.sort(a);
    int sum = 0;
    int i = 0;
    while(true) {
        if (i >= a.length || a[i] > sum + 1) {
            output.add(sum + 1);
            sum += sum + 1;
        } else {
            sum += a[i];
            i++;
        }
        if (sum >= n) {
            break;
        }
    }
    return output.size();
};

我测试了一些案例,看起来是正确的。 但写这篇文章的人没有给我们任何提示,我真的很困惑这个。任何人都可以提出一些解释吗?谢谢!