【问题标题】:Recover original array from all subsets从所有子集中恢复原始数组
【发布时间】:2018-11-12 18:48:23
【问题描述】:

你得到一个数组的所有子集和。然后,您应该从提供的子集总和中恢复原始数组。

保证原始数组中的每个元素都是非负数且小于 10^5。原始数组中的元素不超过 20 个。原始数组也已排序。输入保证有效。

示例 1

如果提供的子集总和是这样的:

0 1 5 6 6 7 11 12

我们可以快速推断出原始数组的大小为 3,因为有 8 (2^3) 个子集。上述输入的输出(即原始数组)是这样的:

1 5 6

示例 2

输入:

0 1 1 2 8 9 9 10

输出:

1 1 8

我尝试了什么

由于保证所有元素都是非负的,因此输入中的最大整数必须是数组的总和。但是,我不确定如何从那里开始。按照逻辑,我认为下一个 (2^2 - 1) 最大的子集总和必须包括数组中除一个元素之外的所有元素。

但是,当原来的数组是这样的时候,上面的逻辑就不行了:

1 1 8

这就是为什么我被卡住并且不确定如何继续。

【问题讨论】:

  • 好的,最小的元素呢?你可以用它做任何事吗?
  • 输入中的最小整数或原始数组中的最小整数中的最小元素?
  • 你确定它是非负数且不是严格正数吗?因为在非负数的情况下,您可以将任意数量的 0 添加到数组中,并且它不会改变它的总和。您将获得无数可能的答案。
  • 你的例子的答案也不正确 - 你的总和包含 0 这一定意味着 0 是原始数组的一部分。
  • 我想我明白为什么 0 不是问题 - 子集的数量唯一标识输入数组的大小。

标签: arrays algorithm subset


【解决方案1】:

这是一个简单的算法,不需要找出哪个子集总和等于给定数字。

S ← 输入序列
X ← 空序列

虽然 S 有一个非零元素:

  1. d ← S 中第二小的元素(最小的总是零)
  2. 在 X 中插入 d
  3. N ← 空序列
  4. 当 S 不为空时:
    • z ← S 的最小元素
    • 从 S 中同时删除 z 和 z+d(如果 S 不包含 z+d,这是一个错误;如果有多个,则只删除 z 和 z+d 的一个实例)。
    • 在 N 中插入 z。
  5. S ← N

输出 X。

【讨论】:

    【解决方案2】:

    假设 S 是子集和数组,A 是原始数组。我假设 S 已排序。

    |A| = log2(|S|)
    S[0] = 0
    S[1] = A[0]
    S[2] = A[1]
    S[3] = EITHER A[2] OR A[0] + A[1].
    

    一般来说,S[i] for i >= 3 要么是 A 的一个元素,要么是你已经遇到过的 A 的元素的组合。在处理 S 时,对于生成给定数字的 A 的每个已知元素组合跳过一次,将任何剩余的数字添加到 A。当 A 达到正确的大小时停止。

    例如,如果 A=[1,2,7,8,9] 那么 S 将包括 [1,2,1+2=3,...,1+8=9, 2+7=9, 9,...]。在处理 S 时,由于 1+8 和 2+7,我们跳过了两个 9,然后看到我们知道必须属于 A 的第三个 9。

    例如,如果 S=[0,1,1,2,8,9,9,10] 那么我们知道 A 有 3 个元素,A 的前 2 个元素是 [1,1],当我们得到到 2 我们跳过它,因为 1+1=2,我们追加 8 并完成,因为我们有 3 个元素。

    【讨论】:

      猜你喜欢
      • 2017-08-06
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多