【问题标题】:Find All Numbers in Array which Sum upto Zero查找数组中总和为零的所有数字
【发布时间】:2015-12-17 07:43:47
【问题描述】:

给定一个数组,输出数组中总和为0的连续元素。

例如:

对于输入[2, 3, -3, 4, -4, 5, 6, -6, -5, 10],

输出为 [3, -3, 4, -4, 5, 6, -6, -5]

我只是找不到最佳解决方案。

说明1:对于输出子数组中的任何元素,子数组中都应该有一个子集,该子数组与该元素相加为零。

例如:对于 -5,subsets {[-2, -3], [-1, -4], [-5], ....} 之一应该存在在输出子数组中。

说明2:输出子数组应该是所有连续的元素。

【问题讨论】:

  • define optimal...你忘了这样做。
  • 还有,什么语言?
  • 提示:对于那些在提出问题后花费接下来的五分钟左右等待 cmets 并对他们做出反应的人来说,会得到很好的答案...
  • 您的“澄清”没有澄清任何内容,因为您滥用术语的方式。您说您找不到“最佳”的方法,但是如果您只是发布您编写的非最佳算法,我们将能够准确理解您的要求。
  • 请下定决心。你想要[3, -3, 4, -4, 5, 6, -6, -5] 还是{[-2, -3], [-1, -4], [-5], ....}

标签: arrays algorithm math satisfiability


【解决方案1】:

根据示例,我假设您只想找到 2 个值加起来等于 0 的值,如果您想包括那些加起来等于 0 的值(例如 5 + - 2 + -3),那么您需要进一步澄清您的参数。

实现因语言而异,但这里有一个展示算法的 javascript 示例,您可以用任何语言实现:

var inputArray = [2, 3, -3, 4, -4, 5, 6, -6, -5, 10];
var ouputArray = [];

for (var i=0;i<inputArray.length;i++){
    var num1 = inputArray[i];

    for (var x=0;x<inputArray.length;x++){
        var num2 = inputArray[x];
        var sumVal = num1+num2;
        if (sumVal == 0){
            outputArray.push(num1);
            outputArray.push(num2);

        }

    }
}

【讨论】:

  • 我很确定您不能只期望找到 +x 和 -x 对。您需要处理 [..., 2, 2, -4, ...]
  • 此解决方案不正确。如果数字的对不相邻,这将重新排列顺序,并将每个数字输出两次。
  • @KennyOstrom 该示例包含-4。 -6 和 10,但没有输出 10。
  • 我同意,这不能处理超过 2 个等于 0 的值。我在编辑中添加了该警告并要求澄清。是的,这将多次列出相同的值,并且也不会遵守原始排序顺序。如果这些是重要功能,则可以重新设计,我只是保持简单,因为对所需功能没有非常明确的定义。
  • 我也漏掉了上面的连续这个词。 OP能否在我努力修改它以增加超过2个值、仅连续、无重复、排序顺序等之前,准确地阐明所需的内容...
【解决方案2】:

这是一个在 O(n³) 中运行的 python 解决方案:

def conSumZero(input):
    take = [False] * len(input)

    for i in range(len(input)):
        for j in range(i+1, len(input)):
            if sum(input[i:j]) == 0:
                for k in range(i, j):
                    take[k] = True;

    return numpy.where(take, input)

编辑:现在更高效了! (不确定它是否相当 O(n²);一旦计算完复杂度就会更新。)

def conSumZero(input):
    take = [False] * len(input)
    cs = numpy.cumsum(input)
    cs.insert(0,0)

    for i in range(len(input)):
        for j in range(i+1, len(input)):
            if cs[j] - cs[i] == 0:
                for k in range(i, j):
                    take[k] = True;

    return numpy.where(take, input)

这里的区别是我预先计算了序列的部分和,并使用它们来计算子序列和 - 因为sum(a[i:j]) = sum(a[0:j]) - sum(a[0:i]) - 而不是每次都迭代。

【讨论】:

  • 我喜欢它,但你不应该开始 j 和结束并向后工作,所以你首先检查最大的解决方案吗?这样,您可以在找到解决方案后立即终止搜索。仅凭目视检查,您似乎会找到所有可能的解决方案,将它们标记为“采取”,然后将它们合并在一起。但是,如果将两个不同的解决方案合并到一个加起来为非零值的输出中呢?
  • 对照 [1, 2, 3, -6, 1, 2] 进行检查
  • @KennyOstrom 我为这个算法检查它们的顺序并不重要。诚然,如果我先从大的开始,我可能会在检查较小的时提前退出,但我现在不想写。这样做是标记属于某个零和子序列的每个元素,然后获取所有标记的元素。如果我标记一个元素两次,它仍然只会被包含一次。
  • @KennyOstrom 在 [1 2 3 -6 1 2] 的情况下,它将输出 [1 2 3 -6 1 2],因为 [1 2 3 -6] 和为 0,并且 [ 3 -6 1 2] 总和为 0。这些子序列包括每个元素,因此每个元素都被标记并随后包含在输出中。
  • 但是输出加起来不等于0,所以你理解我的担心。您将按照修订后的说明进行,其中每个元素都有一个与它相加为 0 的子集,然后忽略原始约束?
【解决方案3】:

为什么不只是散列增量总和并在遍历数组时更新它们的索引,获胜者是索引范围最大的那个。 O(n) 时间复杂度(假设平均哈希表复杂度)。

       [2, 3, -3, 4, -4, 5, 6, -6, -5, 10]
sum  0  2  5   2  6   2  7  13  7   2  12

The winner is 2, indexed 1 to 8!

为了还保证输出数组中每个数字的精确对应连续子数组,我还没有看到检查/散列候选子数组中所有和子序列的方法,这会将时间复杂度提高到@987654323 @。

【讨论】:

  • 当您计算部分和时,您会查找该部分和之前是否发生过,这会为您提供零和子集的开始和结束(以及长度)。存放时间最长。并且您使用哈希表 (dict) 断言 O(1) 进行查找。好的,我喜欢它。也许包括 0 作为第一个总和,以便您可以处理第一个条目为 0 的输入?
  • @KennyOstrom 感谢您的评论。我想我假设起始金额为零;反正我加了。
  • 如果输出总和为 0,则每个项目都有一个由输出数组的所有其余部分组成的精确对应项。
  • @KennyOstrom 不确定您的意思,“每个项目都有一个由输出数组的所有其余部分组成的精确对应项。”能举个简单的例子吗?
  • 输出是一个加起来为 0 的数字列表,例如[50, -5, -10, -15, -20] 并且您需要一种算法来确定对于列表中的任何元素,是否有其他元素的子集相加到该元素中。你担心计算的时间复杂度。我说它是 O(0),因为它是已知的,所以你不必计算它。
【解决方案4】:

这是您要解决的问题吗?

给定一个序列,找到最大化使得

如果是这样,这是解决它的算法:

let $U$ be a set of contiguous integers
for each contiguous $S\in\Bbb Z^+_{\le n}$
    for each $\T in \wp\left([i,j)\right)$
      if $\sum_{n\in T}a_n = 0$
        if $\left|S\right| < \left|U\left$
          $S \to u$

返回 $U$

(一旦有机会,将使用全乳胶进行更新。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-04
    相关资源
    最近更新 更多