Arrays 不能由数组中的数字之和形成的最小数字

Arrays 不能由数组中的数字之和形成的最小数字,arrays,algorithm,data-structures,dynamic-programming,subset-sum,Arrays,Algorithm,Data Structures,Dynamic Programming,Subset Sum,这个问题是在亚马逊采访中问我的- 给定一个正整数数组,必须找到不能由数组中的数字之和构成的最小正整数 例如: Array:[4 13 2 3 1] result= 11 { Since 11 was smallest positive number which can not be formed from the given array elements } 我所做的是: 对数组进行排序 计算前缀和 t反向求和数组并检查下一个元素是否小于1 大于和,即A[j]有一个很好的算法可以在+排序时及

这个问题是在亚马逊采访中问我的-

给定一个正整数数组,必须找到不能由数组中的数字之和构成的最小正整数

例如:

Array:[4 13 2 3 1]
result= 11 { Since 11 was smallest positive number which can not be formed from the given array elements }
我所做的是:

对数组进行排序 计算前缀和 t反向求和数组并检查下一个元素是否小于1
大于和,即A[j]有一个很好的算法可以在+排序时及时解决这个问题,其中排序是对输入数组进行排序所需的时间量

该算法的思想是对数组进行排序,然后问以下问题:使用数组的前k个元素不能生成的最小正整数是多少?然后从左到右向前扫描数组,更新此问题的答案,直到找到无法生成的最小数字

下面是它的工作原理。最初,您不能生成的最小数字是1。然后,从左向右执行以下操作:

如果当前数字大于迄今为止无法生成的最小数字,则您知道无法生成的最小数字-这是您已录制的数字,您已完成。 否则,当前数字小于或等于无法生成的最小数字。声称你确实可以做到这一点。现在,您知道数组的前k个元素不能生成的最小值,称之为候选值,现在正在查看值A[k]。因此,候选数字-A[k]必须是您确实可以使用数组的前k个元素生成的某个数字,因为否则,候选数字-A[k]将比您声称无法使用数组中的前k个元素生成的最小数字小。此外,您可以将范围从“候选对象”到“候选对象+A[k](包括在内)中的任何数字,因为您可以从范围从1到A[k](包括在内)中的任何数字开始,然后将“候选对象-1”添加到该数字中。因此,将candidate设置为candidate+A[k]并递增k。 在伪代码中:

Sort(A)
candidate = 1
for i from 1 to length(A):
   if A[i] > candidate: return candidate
   else: candidate = candidate + A[i]
return candidate
下面是对[4,13,2,1,3]的测试运行。对数组进行排序以获得[1,2,3,4,13]。然后,将candidate设置为1。然后,我们将执行以下操作:

A[1]=1,候选者=1: A[1]≤ 候选者,因此设置候选者=候选者+A[1]=2 A[2]=2,候选者=2: A[2]≤ 候选者,因此设置候选者=候选者+A[2]=4 A[3]=3,候选者=4: A[3]≤ 候选者,因此设置候选者=候选者+A[3]=7 A[4]=4,候选者=7: A[4]≤ 候选者,因此设置候选者=候选者+A[4]=11 A[5]=13,候选者=11: [4]>候选者,因此返回候选者11。 所以答案是11

此处的运行时处于启用+排序状态,因为在排序之外,运行时处于启用状态。您可以使用heapsort在log n time上进行清晰的排序,如果您知道一些数字的上限,您可以在log U上进行时间排序,其中U是使用基数排序的最大可能数字。如果U是一个固定常数,比如说109,那么基数排序在时间上运行,整个算法也在时间上运行


希望这有帮助

考虑区间[2i..2i+1-1]中的所有整数。假设2i以下的所有整数都可以由给定数组中的数字之和构成。还假设我们已经知道C,它是2i以下所有数字的总和。如果C>=2i+1-1,则此间隔内的每个数字都可以表示为给定数字的总和。否则,我们可以检查区间[2i..C+1]是否包含给定数组中的任何数字。如果没有这样的数字,C+1就是我们搜索的

下面是一个算法的示意图:

对于每个输入数字,确定其所属的间隔,并更新相应的和:S[int_logx]+=x。 计算数组S:foreach i:C[i]=C[i-1]+S[i]的前缀和。 过滤数组C以仅保留值小于下一次2次方的条目。
再次扫描输入数组,并注意哪个间隔[2i..C+1]至少包含一个输入编号:i=int_logx-1;B[i]|=x使用位向量在线性时间内完成此操作

从一个空的位向量b开始。然后对数组中的每个元素k执行以下操作:


b=b | b如果您对数组进行排序,它将对您有效。计数排序本可以做到这一点,但若你们认为在一个实际的大场景中,范围可能相当高

*logn上的快速排序将为您完成以下工作:

def smallestPositiveInteger(self, array): 
    candidate = 1
    n = len(array)
    array = sorted(array)
    for i in range(0, n):
        if array[i] <= candidate:
            candidate += array[i]
        else:
            break
    return candidate

你是说面试官要求一个Ologn解决方案吗?这显然是不可能的,因为您必须查看每个数组值一次,这至少需要花费。这里可能需要更具体一些:大于零的最小整数,可能不能通过对数组元素的任何组合求和来创建?数组元素都是正整数吗?是否存在重复?问题的规范是否保证最大可能整数值大大小于INT_MAX?这与昨天提出的问题是否非常相似?在th中应该是candidate=candidate+A[i]
e否则,没有-1。这与OP给出的算法完全相同,但解释非常有用。@user3187810-此解决方案非常快-它的运行速度不比log n时间差,如果可以使用基数排序之类的方法对整数排序,则可能会更好。@interjay:我更新了答案。当我写这篇文章时,我没有意识到它最终与OP的答案完全相同。现在我意识到了这一点,我认为这个答案仍然很有用,因为它为答案提供了一个理由,并展示了如何加快它,即改进排序步骤。但是,如果您认为没有必要,我可以删除这个答案。@user3187810-如果整数有固定的上界,例如10^9,您可以使用计数排序或基数排序及时对它们进行排序。这将使总运行时间降为On。如果数组中的数字是随机生成的,则只需在执行其余算法之前检查是否存在1,就可以在统计上显著提高。请注意,如果位向量操作是常数时间,则这是线性时间,据我所知,没有任何计算机支持在恒定时间内对任意宽度的数字进行位运算。这绝对是一个很酷的主意,但我不认为它真的会出现。@templatetypedef:Fair point。OP在评论中回答说,整数保证在[1,10^9]的范围内,因此可以在开始时以恒定的时间保留足够大的位向量来占据整个空间。即使没有这个余量,每次超出分配的空间时将保留大小加倍也会限制您进行Olg n分配。@DaveGalvin>>是一个移位吗?因为那是右移而不是左移。即使是向左移动,我也一定不明白什么,因为在你的第3步中:1 | 8192 | 1不等于8209。@JonathanMee我写了一个镜像宇宙版本的算法!令人惊讶的是,没有其他人发现或提到它。现在是对的。谢谢你能解释一下{1239}和{1199}的工作原理吗。添加了几个示例。@EvgenyKluev我在看你的示例,我不知道你的S:line是如何计算的。在您的描述中提到了前缀和,但这肯定不是前缀和。@JonathanMee:实际上,C是前缀和,而不是S。S[i]是输入数组中整数对数等于i的值的和。C[i]是整数对数小于或等于i的值之和。@EvgenyKluev感谢你的解释,我现在理解了C和S。但我又被第3步卡住了。我不明白你所说的2的下一次幂是什么意思。
def smallestPositiveInteger(self, array): 
    candidate = 1
    n = len(array)
    array = sorted(array)
    for i in range(0, n):
        if array[i] <= candidate:
            candidate += array[i]
        else:
            break
    return candidate