我遇到了一个算法问题,起初看起来很简单,但我很困惑,不知道该怎么办!问题如下:
假设我们有一个数字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:您还可以引用一些消息来源吗?或告诉我您是如何得出答案的,以及您如何看待此类问题?
答案 0 :(得分:2)
约束有点模糊,但是您可能正在寻找类似的东西:
如果将读取的元素总数相加,将得到2 ^ n + 2 ^(n-1)+ 2 ^(n-2)...,小于2 ^(n + 1),因此O(2 ^ n)
答案 1 :(得分:2)
您这里有2
个案例:
简并的情况:N == 1
很明显。 0 -> 1
和1 -> 0
;您可以说它为~item
常规案例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
。因此,我们有N / 2
个零和N / 2 - 1
个零;所有位的 xor 返回1
0
。因此,我们有N / 2 - 1
个零和N / 2 - 1
个零;所有位的 xor 返回1
由于^
是按位运算(第j
位的值与第i
位的值无关),我们证明了位是正确的,整个值也是正确的。