修改子集和

时间:2014-01-25 09:35:59

标签: arrays algorithm

给定一组N个正整数。设最小元素为L,所有元素之和为S.

我需要找出,对于每个整数X,(其中X在L和S之间),可以选择数组的子集,使得该子集中的元素总和等于X.

示例

N=5和数组为{4,8,2,1,16}。然后这里所有元素都可以在1到31之间进行,所以这里的答案是“是”。

如果假设N=4且数组为{5,1,2,7}。然后,对于1到15之间的值,不能进行值4和11。 所以这里的回答是“不”。

2 个答案:

答案 0 :(得分:2)

  

我知道找到这个数组不能返回的最小数字,但不知道如何解决这个问题

首先,数组只有一个元素吗?如果是这样,答案是肯定的。

否则,找到最小的不可能总和。它比S大吗?如果是这样,答案是肯定的。否则,答案是否定的。 (如果最小值小于L,则数组不包含1,并且S-1是不可能的总和。)

要找到最低的不可能总和,我们对输入进行排序,然后找到数组每个前缀的最低不可能总和。在Python中:

def lowest_impossible_sum(nums):
    nums = sorted(nums)
    partial_sum = 0
    for num in nums:
        if num > partial_sum + 1:
            return partial_sum + 1
        partial_sum += num
    return partial_sum + 1

通过归纳证明正确性:

设A为排序数组。如果A[0] > 1,则1是最低的不可能总和。否则,A[:1]的元素可以产生最多sum(A[:1])的所有总和。

假设可以选择A[:k]的子集来生成最多sum(A[:k])的所有总和。

  • 如果A[k] > sum(A[:k]) + 1,则sum(A[:k]) + 1是最低的不可能总和;它不能由A[:k]的子集生成,添加不在A[:k]中的元素也无济于事,因为它们太大了。
  • 如果A[k] <= sum(A[:k]) + 1,那么A[:k+1]的子集可以产生最多sum(A[:k+1])的总和。诱导假设已经可以生成sum(A[:k])的每个总和,并且可以通过选择sum(A[:k]) + 1和{{1}的合适子集来生成sum(A[:k+1])A[k]的总和。添加到剩下的内容。

如果没有这样的索引,则让x成为A[:k]A[x] > sum(A[:x]) + 1的第一个索引。通过归纳,每个总和可达len(A)。但是,无论是因为x超出数组的末尾还是因为sum(A[:x]),都不可能产生总和A[x] > sum(A[:x]) + 1。因此,我们只需要搜索x并返回sum(A[:x]) + 1。这就是算法的作用。

答案 1 :(得分:0)

首先对数组中的所有元素进行排序。如果你想从数组的元素中得到L和S之间的所有值,那么 L = 1 ,元素应该是2 ^ i的形式。并且最大元素可能不是2 ^ i形式,因为总和不需要是形式(2 ^ i - 1)。