最少添加数字 - 算法

时间:2015-07-13 23:24:58

标签: algorithm

我在网上遇到过这个问题。

  

给定一个整数:N和一个数组int arr [],你必须添加一些   数组元素,以便您可以使用生成从1到N.   (添加)数组中的元素。

请记住,在生成某个x(1 <= x <= N)时,您只能使用数组中的每个元素。返回最少添加数字的数量。

For example:

N=6, arr = [1, 3] 

1 is already in arr. 

add 2 to the arr. 

3 is already in arr 

4 = 1 + 3 

5 = 2 + 3 

6 = 1 + 2 + 3 

So we return 1 since we only need to add one element which is 2.

任何人都可以提供一些提示吗?

4 个答案:

答案 0 :(得分:4)

N始终可以通过将1的子集添加到除N - 1N = 2之外的N = 1个数字来制作。因此,当先前的X1个连续元素已经在数组中时,必须可以生成X - 1个数字。 示例 -

    arr[] = {1, 2, 5}, N = 9
    ans := 0
    1 is already present.
    2 is already present.
    3 is absent. But prior 1 to (3 - 1) elements are present. So 3 is added in the array. But as 3 is built using already existed elements, so answer won't increase.
    same rule for 4 and 5

    So, ans is 0

    arr[] = {3, 4}, for any N >= 2

    ans = 2

    arr[] = {1, 3}, for any N >= 2

    ans = 1

所以,似乎如果数组中不存在12,我们必须添加该元素,而不管之前的元素是否已经存在于数组中。以后的所有数字都可以使用以前的元素。在尝试创建任意数字X(&gt; 2)时,我们已经在数组中找到了之前的1X - 1元素。所以X总是可以制作。

因此,基本上我们需要检查12是否存在。因此,这个问题的答案不会大于2

约束2

在上面的算法中,我们假设,当数组中不存在新元素X但可以使用已存在的数组元素进行制作时,则答案不会增加X将添加到数组中以用于下一个数字构建。如果无法在数组中添加X该怎么办?

然后,基本上它将变成子集和问题。对于每个缺失的数字,我们必须检查数字是否可以使用数组中的任何元素子集。它是一种典型的O(N^2)动态编程算法。

int subsetSum(vector<int>& arr, int N)
{
    // The value of subset[i][j] will be true if there is a subset of set[0..j-1]
    //  with sum equal to i
    bool subset[N + 1][arr.size() + 1];

    // If sum is 0, then answer is true
    for (int i = 0; i <= arr.size(); i++)
      subset[0][i] = true;

    // If sum is not 0 and set is empty, then answer is false
    for (int i = 1; i <= N; i++)
      subset[i][0] = false;

     // Fill the subset table in botton up manner
     for (int i = 1; i <= N; i++)
     {
       for (int j = 1; j <= arr.size(); j++)
       {
         subset[i][j] = subset[i][j - 1];
         if (i >= set[j - 1])
           subset[i][j] = subset[i][j] || subset[i - set[j - 1]][j - 1];
       }
     }

     unordered_map<int, bool> exist;
     for(int i = 0; i < arr.size(); ++i) {
         exist[arr[i]] = true;
     }

     int ans = 0;
     for(int i = 1; i <= N; ++i) {
          if(!exist[i] or !subset[i][arr.size()]) {
              ans++;
          }
     }

     return ans;
}

答案 1 :(得分:3)

设A为输入数字的集合。

初始化一个布尔数组B以存储在B [i]中,无论我们是否可以通过在问题中描述的A中添加数字来“制造”i。使所有B [i]最初都为FALSE。

然后,伪代码:

for i = 1 to N

     if B[i] && (not A.Contains(i))
        continue next i

      if not A.Contains(i)
        countAdded++

      for j = N-i downTo 1
        if B[j] then B[j+i] = TRUE

      B[i] = TRUE

    next i

说明:

在(主)循环(i)中:对于我们可以使用A中的值低于i构造的值,B包含TRUE。因此,最初,如果i = 1,则所有B都为FALSE。

然后,对于每个我,我们有两个方面需要考虑:(a)B [i]是否已经为真?如果不是,我们将不得不添加i; (b)我是否在A?因为,见前面的评论,此时我们尚未处理该A值。因此,即使B [i]已经为TRUE,我们也必须为我们可能与i达成的所有(其他)B标记为TRUE。

因此:

对于每一个我们首先确定这两个案例中的任何一个是否适用,如果不适用,我们跳到下一个i。

然后,如果A不(还)包含i,则必须是B [i]为FALSE的情况,请参阅skip-condition,因此我们将添加i(在概念上添加到A,但不是必需的实际上把它放入A)。

接下来,要么我们最初在A中,或者我们刚刚添加了它。在任何情况下,我们都需要为可以用这个新i构造的所有值标记B TRUE。为此,我们更好地以向下的方式扫描现有的B;否则我们可能会将i添加到已经作为成分的“新”B值。

最后,B [i]本身设置为TRUE(它可能已经为TRUE ......),因为我在A中(或者通过添加)

答案 2 :(得分:2)

  • 对阵列进行排序(NLogN)
  • 认为这应该有效 -
max_sum = 0
numbers_added = 0 # this will contain you final answer
for i in range(1, N+1):
    if i not in arr and i > max_sum:
        numbers_added += 1
        max_sum += i
    elif i < len(arr):
        max_sum += arr[i]
print numbers_added

答案 3 :(得分:2)

对于从1开始的每个数字,我们可以

  1. 把它放在arr中。在这种情况下,我们会更新我们可以制作的数字列表。

  2. 不要在arr中使用它,但我们可以使用现有数字形成它。我们完全忽略它。

  3. 我们在arr中没有它,我们无法用现有数字形成它。我们将它添加到arr并更新我们可以制作的数字列表。

    For example:
    
    N=10, arr = [1, 2, 6] 
    
    1 is already in arr. 
    
    2 is already in arr. 
    
    3 = 1 + 2
    
    3 is not in the arr but we can already form 3.
    
    4 is not present in arr and we cannot form 4 either with existing numbers.
    So add 4 to the arr and update.
    
    5 = 1 + 4
    
    6 = 2 + 4
    
    7 = 1 + 2 + 4
    
    5 is not in arr but we can form 5. 
    
    6 is in array. So update
    
    8 = 2 + 6
    
    9 = 1 + 2 + 6
    
    10 = 4 + 6
    
    So we return 1 since we only need to add one element which is 4.
    
  4. 以下可能是一个实现:

    int calc(bool arr[], bool can[], int N) {
        // arr[i] is true if we already have number 
        // can[i] is true if we have been able to form number i
    
        int count=0;
        for(int i=1;i<=N;i++) {
            if(arr[i]==false && can[i]==true) {  // case 1
                continue;
            } else if(arr[i]==false && can[i]==false) {  // case 3
                count++;
            }
            for(int j=N-i;j>=1;j--) {  // update for case 1 and case 3
                if(can[j]==true) can[i+j]=true;
            }
            can[i]=1;
        }
        return count;
    }