C++ 处理N中的M个事件
我在面试时被问到的问题。我很接近解决方案,但不幸没有解决 假设我们有一个序列,其中包含N个C++ 处理N中的M个事件,c++,arrays,algorithm,C++,Arrays,Algorithm,我在面试时被问到的问题。我很接近解决方案,但不幸没有解决 假设我们有一个序列,其中包含N个long类型的数字。我们可以肯定地知道,在这个序列中,除了一个数字精确地出现了m次(0
long
类型的数字。我们可以肯定地知道,在这个序列中,除了一个数字精确地出现了m次(0<mn)之外,每个数字确实出现了n次。在O(N)运算和O(1)额外内存的情况下,我们如何找到这个数字
对于最简单的情况(当n=2和m=1),我们所要做的就是对序列中的每个数字执行累加的xor
。结果将等于所需的数字。但是我在处理任意的m和n时被卡住了
我很欣赏一个实际的C++解决方案。
编辑:我们事先知道m和n的实际值 示例。我们知道n=3和m=2。序列(N=8)为
在这种情况下,正确的答案是2,因为它只出现两次。最简单的情况可以更一般,你可以使用你为奇数m和偶数n描述的相同技术,如果对列表进行排序,那么这变得非常简单,因为你只需要依次检查每个批次的长度是否为m 如果列表没有排序,那么我认为使用O(1)个额外内存是不可能的。编辑)好的,这个方法不像我最初认为的那样可靠。eBusiness的解决方案简单得多,在n=4、m=2等情况下都能正常工作。 我们可以将异或方法推广到任意m和n。我们首先需要选择一个基础b,这样gcd(n,b)=b,并且gcd(m,b)。由于奇数n/偶数m对满足基数2的要求,标准二进制异或适用于这些对 首先,我们将(a^^n)定义为(a^^a^…^a)表示n a,具有基b的广义异或。例如,对于标准二进制异或,a^^2=0 我们需要定义我们的广义异或。我们想要的性质基本上与加法(交换性、结合性)相同,我们需要a^^b=0。显而易见的解决方案是,对于基表示中的每个数字,(x^y)=(x+y)%b(请相信这是可行的,并且与基2的二进制异或相同)。然后,我们简单地将其应用于序列中的所有数字,并最终得到结果=s^^(m%b),其中s是特殊数字。
最后,我们需要将我们的“异或”基数b还原为预期的数字。我们可以简单地计算i=0..b-1的i^(m%b),然后查找结果中每个数字在s中的值 该算法是O(N)的。对于列表中的每个数字,我们要做的操作数是恒定的,因为我们最多有64位数字。对于大b,在末端恢复最差为O(N)。我们可以在常量空间中通过计算每个数字的所有i的i^^(m%b)来完成最后一步(同样,我们有一个恒定的位数)
例子: n=3,m=2。列表=
[5 11 5 2 11 5 2 11]
首先,我们选择一个基b。显然,我们必须选择基数3
xor表供参考:
0|1|2
0|0|1|2
1|1|2|0
2|2|0|1
计算:
5 11 5 2 11 5 2 11
0^0=0. 0^1=1. 1^0=1. 1^0=1. 1^1=2. 2^0=2. 2^0=2. 2^1=0.
0^1=1. 1^0=1. 1^1=2. 2^0=2. 2^0=2. 2^1=0. 0^0=0. 0^0=0.
0^2=2. 2^2=1. 1^2=0. 0^2=2. 2^2=1. 1^2=0. 0^2=2. 2^2=1.
m % b = 2.
因此我们有s^^2=[001]。我们为每个数字i生成一个i^^2表,然后进行反向查找
i | 0 | 1 | 2 |
i^^2 | 0 | 2 | 1 |
0 -> 0
0 -> 0
1 -> 2
最后,我们将结果转换回二进制/十进制。[002]=2.- 如果对从0到(N/N)+1的整数集进行一对一哈希运算,则可以通过N次迭代+N/N次迭代(使用N个内存)来求解。但是,没有一对一的映射
- 如果没有对内存的限制,那么它必须是常量。您可以定义一个数组,其大小为long域的大小,这样您就可以在2N中解决这个问题,同时使用恒定的庞大内存。对于N中的每一个x,您只需添加到BIGARRY[x],然后在BIGARRY中循环寻找m。它很糟糕,不可实施,但符合要求,大多数面试问题都是思想实验
- m
- n
- x_1 x_2。。x_N
sum(x_i) = n * sum(U_1) + m * u_0 = n * sum(U) + (m - n) * u_0
解决这个问题相当于在一个序列中求唯一元素的和,而你不能在O(1)个额外的空间中这样做,因为你需要一个带有链接元素的数组或哈希表-这个空间实际上是O(N)你需要64个和,每个位一个,每个和你计算的sum mod N,对于结果中应设置的每个位,此计算返回m,对于不应设置的每个位,返回0 示例:
n=3,m=2。列表=[5 11 5 11 5 2 11]
5 11 5 2 11 5 2 11
sum of bit 0: 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 = 6 6 % 3 = 0
sum of bit 1: 0 + 1 + 0 + 1 + 1 + 0 + 1 + 1 = 5 5 % 3 = 2
sum of bit 2: 1 + 0 + 1 + 0 + 0 + 1 + 0 + 0 = 3 3 % 3 = 0
sum of bit 3: 0 + 1 + 0 + 0 + 1 + 0 + 0 + 1 = 3 3 % 3 = 0
所以只设置了位1,这意味着结果是2
优化实施:(对实际问题同样有用的技巧和注意事项)
值得注意的是,当在数组上迭代时,如果需要执行多线程,执行速度将在一定程度上受到内存访问的限制
5 11 5 2 11 5 2 11
sum of bit 0: 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 = 6 6 % 3 = 0
sum of bit 1: 0 + 1 + 0 + 1 + 1 + 0 + 1 + 1 = 5 5 % 3 = 2
sum of bit 2: 1 + 0 + 1 + 0 + 0 + 1 + 0 + 0 = 3 3 % 3 = 0
sum of bit 3: 0 + 1 + 0 + 0 + 1 + 0 + 0 + 1 = 3 3 % 3 = 0
1000 1000 1000 1000 +
1000 0000 0000 1000 +
0000 0000 0000 1000 +
1000 1000 0000 0000 +
1000 0000 1000 0000 +
0000 0000 1000 1000 =
0010 0100 1100 0010
int divider = 0;
for (int i = 63; i >= 0; i--) {
divider |= 1 << i;
int a = countAbove(divider);
int b = countBelow(divider);
if (a % n == 0 && b % n == 0) return divider;
else if (a % n == 0) divider ^= 1 << i;
}
by dividing the sequence into 2 sub-seqs
(calculate the size of sub-seqs during the procedure)
while (sizeof(sub-seq) mod n != 0)
do the same porcess on this sub-seq(dividing)