您有一个数组,其中每个数字都重复奇数次(但不止一次出现)。恰好一个数字出现一次。您如何找到仅出现一次的号码?
e.g.: {1, 6, 3, 1, 1, 6, 6, 9, 3, 3, 3, 3}
答案是9。
我正在考虑拥有一个哈希表,然后仅对计数为1的元素进行计数。这似乎是微不足道的,并且我没有利用其他元素重复奇次的事实。有没有更好的方法。
我相信您仍然可以使用XOR的基本思想来巧妙地解决此问题。
首先,让我们更改问题,以使一个数字出现一次,而所有其他数字出现三次。
算法:
这A是length的数组n:
A
n
int ones = 0; int twos = 0; int not_threes, x; for (int i=0; i<n; ++i) { x = A[i]; twos |= ones & x; ones ^= x; not_threes = ~(ones & twos); ones &= not_threes; twos &= not_threes; }
恰好发生一次的元素存储在中ones。这会占用O(n)时间和O(1)空间。
ones
O(n)
O(1)
我相信我可以将这个想法扩展到问题的一般情况,但是也许你们中的一个可以更快地做到这一点,所以我现在将其保留,并在何时以及是否可以推广该解决方案时对其进行编辑。
说明:
如果问题是这样的:“一个元素出现一次,所有其他元素出现偶数次”,那么解决方案将是对元素进行XOR。原因是x^x = 0,因此所有成对的元素都将消失,仅留下孤独的元素。如果我们在这里尝试相同的策略,那么我们将得到不同元素的XOR,这不是我们想要的。
x^x = 0
而是,上述算法执行以下操作:
twos
每次当我们x成为数组中的下一个元素时,都会出现以下三种情况:
x
因此,最后ones将是仅一个元素的XOR,即不再重复的孤独元素。我们需要查看5行代码以了解其工作原理:后五行x = A[i]。
x = A[i]
如果这是第一次x出现,那么ones&x=ones这样twos保持不变。行ones ^= x;异或x与ones权利。因此x在恰好一个ones和twos,所以没有在最后三行要么发生ones或twos。
ones&x=ones
ones ^= x;
如果这是第二次x出现,则ones已经有x(通过上面的说明),所以现在twos用line来获取它twos |= ones & x;。此外,由于ones具有x,因此该行从中ones ^= x;删除(因为)。再次,最后三行自做的正好一个没有和现在有。x``ones``x^x=0``ones``twos``x
twos |= ones & x;
x``ones``x^x=0``ones``twos``x
如果这是第三次x出现,则ones没有x,但twos确实。因此,第一行让我们twos继续x,第二行添加x到ones。现在,由于两者都具有ones并且twos具有x,因此最后三行x将从两者中删除。
概括:
如果一些数字出现5次,则此算法仍然有效。这是因为第4次未x出现,也不ones是twos。前两行,然后添加x到ones,而不是twos最后三行什么也不做。第5次x出现,ones但不在twos。第一行将其添加到中twos,第二行将其从中删除ones,最后三行不执行任何操作。
问题是第6次x出现,它是从ones和提取的twos,因此它ones在第7次传回时又添加回去。我正在尝试一种聪明的方法来防止这种情况,但是到目前为止,我还是空虚的。