我是C ++的新手,需要在以下任务中提供逻辑帮助。
给定n个正整数的序列(n <10 ^ 6;每个给定的整数小于10 ^ 6),编写程序以找到最小的正整数,其不能表示为1,2的总和或者给定序列的更多项目(即每个项目可以被取0或1次)。示例:输入:2 3 4,输出:1;输入:1 2 6,输出:4
我似乎无法构造它的逻辑,为什么最后的输出是4以及如何在C ++中实现它,非常感谢任何帮助。 到目前为止,这是我的代码:
#include<iostream>
using namespace std;
const int SIZE = 3;
int main()
{
//Lowest integer by default
int IntLowest = 1;
int x = 0;
//Our sequence numbers
int seq;
int sum = 0;
int buffer[SIZE];
//Loop through array inputting sequence numbers
for (int i = 0; i < SIZE; i++)
{
cout << "Input sequence number: ";
cin >> seq;
buffer[i] = seq;
sum += buffer[i];
}
int UpperBound = sum + 1;
int a = buffer[x] + buffer[x + 1];
int b = buffer[x] + buffer[x + 2];
int c = buffer[x + 1] + buffer[x + 2];
int d = buffer[x] + buffer[x + 1] + buffer[x + 2];
for (int y = IntLowest - 1; y < UpperBound; y++)
{
//How should I proceed from here?
}
return 0;
}
答案 0 :(得分:4)
Voreno建议的答案实际上是解决0-1背包问题(http://en.wikipedia.org/wiki/Knapsack_problem#0.2F1_Knapsack_Problem)。如果您按照链接,您可以阅读如何在不构建初始集的所有子集的情况下完成它(它们太多,2 ^ n)。如果约束条件有点小,就像10 ^ 3那样它会起作用。
但是当n = 10 ^ 6时,它仍然需要太多的时间和空间。但是没有必要解决背包问题 - 我们只需要找到我们无法获得的第一个数字。
更好的解决方案是对数字进行排序,然后迭代一次,找到数组的每个前缀数x,这样使用该前缀就可以得到区间[1..x]中的所有数字。此时我们无法获得的最小数字是x + 1.当您考虑下一个数字a [i]时,您有两个选择:
示例:
您将获得数字1,4,12,2,3。
你对它们进行排序(得到1,2,3,4,12),从x = 0开始,考虑每个元素并按以下方式更新x:
1&lt; = x + 1,因此x = 0 + 1 = 1。
2&lt; = x + 1,因此x = 1 + 2 = 3。
3 <= x + 1,因此x = 3 + 3 = 6.
4&lt; = x + 1,因此x = 6 + 4 = 10.
12&gt; x + 1,所以我们找到了答案,它是x + 1 = 11。
(编辑:修正了一个错误,添加了示例。)
答案 1 :(得分:3)
我认为这可以在O(n)时间和O(log2(n))存储器复杂性中完成。 假设使用O(1)中的BSR(最高设置位索引)(floor(log2(x)))实现。
算法:
1创建一个(log2(MAXINT))桶的数组,在10 ^ 6的情况下为20,每个桶包含sum和min值(init:min = 2 ^(i + 1)-1,sum = 0 )。 (懒惰的初始化可以用于小n)
2对输入进行一次传递,将每个值存储在桶[bsr(x)]中。
for (x : buffer) // iterate input
buckets[bsr(x)].min = min(buckets[bsr(x)].min, x)
buckets[bsr(x)].sum += x
3迭代桶,维持无法访问:
int unreachable = 1 // 0 is always reachable
for(b : buckets)
if (unreachable >= b.min)
unreachable += b.sum
else
break
return unreachable
这是有效的,因为假设我们在桶i,我们考虑两种情况:
不可达&gt; = b.min为真:因为该桶包含范围[2 ^ i ... 2 ^(i + 1)-1]中的值,这意味着2 ^ i <= b。分钟。反过来,b.min&lt; =无法到达。因此无法到达+ b.min&gt; = 2 ^(i + 1)。这意味着可以添加桶中的所有值(在添加b.min之后,所有其他值都更小),即无法访问+ = b.sum。
unreachable&gt; = b.min为false:这意味着b.min(剩余序列中的最小数字)大于不可达。因此我们需要返回无法访问。
答案 2 :(得分:0)
第二个输入的输出为4,因为如果您只能将每个项目仅取0或1次,则这是最小的正数,不能表示为1,2或6的总和。我希望这可以帮助你理解更多:
该列表中有3个项目:1,2,6 从最小的正整数开始,您开始检查该整数是否可以是给定序列的1个或更多个数之和的结果。
1 = 1+0+0
2 = 0+2+0
3 = 1+2+0
4 cannot be expressed as a result of the sum of one of the items in the list (1,2,6). Thus 4 is the smallest positive integer which cannot be expressed as a sum of the items of that given sequence.
答案 3 :(得分:-1)
最后一个输出是4,因为:
1 = 1
2 = 2
1 + 2 = 3
1 + 6 = 7
2 + 6 = 8
1 + 2 + 6 = 9
因此,输入(1,2,6)的任何组合都无法表示的最小整数为4.
问题是: 第1部分。找到可以由输入数字表示的最大可能整数(即,给出的所有数字的总和),它给出了上限
UpperBound = sum(all_your_inputs) + 1
第2部分。通过组合您给出的不同整数,找到您可以获得的所有整数。即如果给你a,b和c作为整数,找到:
a + b,a + c,b + c和a + b + c
第2部分)+整数列表,为您提供使用数字可以获得的所有整数。
从1到UpperBound的每个整数循环
表示i = 1到UpperBound 如果我不是=从第2点开始的列表中的数字) i =你的最小整数 破
这是一种笨拙的做法,但我确信通过一些数学可以找到更好的方法吗?
编辑:改进的解决方案
//sort your input numbers from smallest to largest
input_numbers = sort(input_numbers)
//create a list of integers that have been tried numbers
tried_ints = //empty list
for each input in input_numbers
//build combinations of sums of this input and any of the previous inputs
//add the combinations to tried_ints, if not tried before
for 1 to input
//check whether there is a gap in tried_ints
if there_is_gap
//stop the program, return the smallest integer
//the first gap number is the smallest integer