我在网上遇到过这个问题。
给定一个整数: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.
任何人都可以提供一些提示吗?
答案 0 :(得分:4)
N
始终可以通过将1
的子集添加到除N - 1
和N = 2
之外的N = 1
个数字来制作。因此,当先前的X
到1
个连续元素已经在数组中时,必须可以生成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
所以,似乎如果数组中不存在1
和2
,我们必须添加该元素,而不管之前的元素是否已经存在于数组中。以后的所有数字都可以使用以前的元素。在尝试创建任意数字X
(&gt; 2)时,我们已经在数组中找到了之前的1
到X - 1
元素。所以X
总是可以制作。
因此,基本上我们需要检查1
和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)
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开始的每个数字,我们可以
把它放在arr中。在这种情况下,我们会更新我们可以制作的数字列表。
不要在arr中使用它,但我们可以使用现有数字形成它。我们完全忽略它。
我们在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.
以下可能是一个实现:
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;
}