Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 处理N中的M个事件_C++_Arrays_Algorithm - Fatal编程技术网

C++ 处理N中的M个事件

C++ 处理N中的M个事件,c++,arrays,algorithm,C++,Arrays,Algorithm,我在面试时被问到的问题。我很接近解决方案,但不幸没有解决 假设我们有一个序列,其中包含N个long类型的数字。我们可以肯定地知道,在这个序列中,除了一个数字精确地出现了m次(0

我在面试时被问到的问题。我很接近解决方案,但不幸没有解决

假设我们有一个序列,其中包含N
long
类型的数字。我们可以肯定地知道,在这个序列中,除了一个数字精确地出现了m次(0<mn)之外,每个数字确实出现了n次。在O(N)运算和O(1)额外内存的情况下,我们如何找到这个数字

对于最简单的情况(当n=2和m=1),我们所要做的就是对序列中的每个数字执行累加的
xor
。结果将等于所需的数字。但是我在处理任意的mn时被卡住了

我很欣赏一个实际的C++解决方案。
编辑:我们事先知道mn的实际值

示例。我们知道n=3和m=2。序列(N=8)为


在这种情况下,正确的答案是2,因为它只出现两次。

最简单的情况可以更一般,你可以使用你为奇数m和偶数n

描述的相同技术,如果对列表进行排序,那么这变得非常简单,因为你只需要依次检查每个批次的长度是否为m

如果列表没有排序,那么我认为使用O(1)个额外内存是不可能的。

编辑)好的,这个方法不像我最初认为的那样可靠。eBusiness的解决方案简单得多,在n=4、m=2等情况下都能正常工作。 我们可以将异或方法推广到任意mn。我们首先需要选择一个基础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-1i^(m%b),然后查找结果中每个数字在s中的值

该算法是O(N)的。对于列表中的每个数字,我们要做的操作数是恒定的,因为我们最多有64位数字。对于大b,在末端恢复最差为O(N)。我们可以在常量空间中通过计算每个数字的所有ii^^(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
由于x_i值之间存在重复项,因此让我们将U定义为唯一值集。U中的所有元素出现n次,其中一个元素在x_i系列中出现m次。让我们将出现频率较低的元素标记为u_0,u_1标记为集合u-{u_0}

让我们是所有x_i的总和。S可以写成:

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)