【问题标题】:Algorithm: Find single number in array算法:在数组中查找单个数字
【发布时间】:2017-05-21 19:10:02
【问题描述】:

这是我刚刚看到的一个 leetcode 问题。有人给出的解决方案有点难以理解,我希望有人能详细说明一下:

给定一个整数数组,每个元素都会出现 3 次,但只有一个元素只出现一次。找到那个。

在没有额外空间的线性时间内执行此操作。

有人给出的解决方案:

public int singleNumber(int[] A) {
    int ones = 0, twos = 0;
    for(int i = 0; i < A.length; i++){
        ones = (ones ^ A[i]) & ~twos;
        twos = (twos ^ A[i]) & ~ones;
    }
    return ones;
}

这似乎是一个很棒的解决方案,但有点难以理解。 cmets 中有人说这可以扩展到任意数量的重复。

【问题讨论】:

  • 如果每个元素出现两次,除了一个,那么你可以对所有数字进行异或。我想这是适应了 3 次。
  • 使用数组[n, n, n],可以看到变量取值n, 00, n0, 0。现在只需表明数组的顺序无关紧要。

标签: algorithm


【解决方案1】:

假设对于 int 中的每个位,您都有一个计数器。该计数器可以取值 0、1 或 2。对于输入数字中的每 1 位,您递增相应的计数器,当您达到 3 时循环回 0。

如果一个数字在数组中出现 3 次,则其 1 位对应的计数器将对该数字递增 3 次,最终无效。出现一次的数字,其对应的计数器会增加一次,所以最后,计数器将只反映出现一次的数字的 1 位。

这基本上是“异或一切”解决方案的三元版本,如果重复数字出现 2 次而不是 3 次,您将使用该解决方案。我们可以进一步使用三元并使用输入的基数 3 位而不是位,但位更容易使用。


onestwos 变量用于维护这些计数器。 ones 变量中的 1 位对应于计数器值 1,twos 变量中的 1 位对应于计数器值 2。计数器值 0 对应于 onestwos.

这个:

ones = (ones ^ A[i]) & ~twos;
twos = (twos ^ A[i]) & ~ones;

是计数器更新。一点一点的看。

如果 A[i] 中的某个位设置为 0,则这些行不会影响 onestwos 中的该位。

如果A[i] 中的某个位设置为 1,则

  • 如果该位在ones 中设置,则在ones 中未设置(因为^ A[i])并在twos 中设置(因为^ A[i],然后&amp; ~ones 不会取消设置这是因为我们只是取消了ones 中的位)。
  • 如果在twos 中设置了该位,则它在ones 中保持未设置状态(因为&amp; ~twos)并在twos 中保持未设置状态(因为^ A[i])。
  • 如果该位在onestwos 中均未设置,则它将在ones 中设置(因为^ A[i])并在twos 中保持未设置状态@(因为&amp; ~ones)。

最后,ones 的位设置对应于仅出现一次的A 的元素,因此我们返回ones

【讨论】:

  • 这是一个很好的看待它的方式。谢谢你的解释。
猜你喜欢
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 2010-09-13
  • 2015-07-22
  • 1970-01-01
  • 2020-10-25
  • 2017-05-08
  • 2021-10-16
相关资源
最近更新 更多