在2 ^ n时间找到n * 2 ^ n矩阵中的缺失行算法问题

时间:2018-11-16 05:09:31

标签: algorithm matrix powerset

我遇到了一个算法问题,起初看起来很简单,但我很困惑,不知道该怎么办!问题如下:

假设我们有一个数字n,然后有一个n列和2 * n行的矩阵。就像幂集(例如,对于n = 2,我们有10,11,00,01)。这些行不一定遵循任何顺序。我们也可以在O(1)时间访问每个矩阵成员。现在,我们有(2 ^ n)-1个行,我们想在最短的时间内找到最后一行(请注意,有n *(2 ^ n-1)个成员,而我们只有O(2 ^ n)时间。我们应该怎么做? (我们有O(n)内存。尽管我不确定是否足够。如果您知道使用任何内存量的答案都可以)

示例输入:

3
101
110
100
000
111
011
010

示例输出:001

我试图通过流行的丢失位问题(通过对矩阵成员进行异或运算)对它进行建模,但是进展不大。

P.S。在C / C ++ / Java / Python上实现该算法的过程将很受赞赏,因为它可以使事情变得清晰起来。

P.S.S:您还可以引用一些消息来源吗?或告诉我您是如何得出答案的,以及您如何看待此类问题?

2 个答案:

答案 0 :(得分:2)

约束有点模糊,但是您可能正在寻找类似的东西:

  • 检查所有2 ^ n行中的第一项,以确定缺失行中的第一项。 1或零将开始2 ^(n-1)行,另一个选项将开始2 ^(n-1)-1行-计数较低的项将开始丢失行。
  • 检查2 ^(n-1)-1行中与缺失行相同的第二项,以找到缺失行中的第二项。
  • 继续在缺失的行中查找所有n个项目。

如果将读取的元素总数相加,将得到2 ^ n + 2 ^(n-1)+ 2 ^(n-2)...,小于2 ^(n + 1),因此O(2 ^ n)

答案 1 :(得分:2)

您这里有2个案例:

  1. 简并的情况:N == 1很明显。 0 -> 11 -> 0;您可以说它为~item

  2. 常规案例N > 1。您要做的就是异或所有值:

    101 ^ 110 ^ 100 ^ 000 ^ 111 ^ 011 ^ 010 == 001

该算法具有O(N * 2**N)的时间复杂度(我们必须读取矩阵的每个单元格),并且需要O(n)空间(在“异或”时存储时间总和)。

C#实现( Linq ):

  string source = "3 101 110 100 000 111 011 010";

  // "001"
  // new char[] { ' ', '\r', '\n', 't' } - to be on the safe side -
  // whatever delimiter is we'll get a correct array
  string result = source
    .Split(new char[] { ' ', '\r', '\n', 't' }, StringSplitOptions.RemoveEmptyEntries)
    .Skip(1) // we don't want "3"
    .Aggregate((sum, item) =>  // xoring strings
       string.Concat(sum.Zip(item, (x, y) => (char)((x - '0') ^ (y - '0') + '0'))));

让我们证明算法的正确性(N > 1)。

由于N > 1以及2**N >= 4以来,2**(N - 1)是一些偶数值。让我们看一下电源系列的所有2**N项的任意位

 000...0...0
 000...0...1
  ...
 111.......0
 111...1...1
       ^
     - N/2 '0's (even) and N/2 '1' (even), xor == 0

我们发现我们正好有N / 2个零和N / 2个零;所有这些位中的 xor 是距离0(因为N / 2 == 2**(N - 1)是一些偶数)。 如果错过了一行,例如0...1...1我们有2的可能性:

  1. 缺少的位是1。因此,我们有N / 2个零和N / 2 - 1个零;所有位的 xor 返回1
  2. 缺少的位是0。因此,我们有N / 2 - 1个零和N / 2 - 1个零;所有位的 xor 返回1

由于^按位运算(第j位的值与第i位的值无关),我们证明了位是正确的,整个值也是正确的。