![](/img/trans.png)
[英]How can I find a number which occurs an odd number of times in a SORTED array in O(n) time?
[英]How to find number of 1's in a binary number in O(1) time?
我知道之前有人问过,但我正在看这里列出的特定解决方案:
int BitCount(unsigned int u)
{
unsigned int uCount;
uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
它是如何工作的?
这里有什么警告吗?
理论上可以在恒定的时间内找到答案吗? 我的意思是,我们实际上不必迭代这些位来计算?
无符号的32位整数u
可以这样写:
u = a 31 * 2 31 + a 30 * 2 30 + ... + a 0 * 2 0
我们想要a 31 + a 30 + ... + a 0
。
让我们比较一下u >> k
的值:
u >> 0 = a31 * 231 + a30 * 230 + ... + a1 * 21 + a0 * 20 u >> 1 = a31 * 230 + a30 * 229 + ... + a1 * 20 u >> 2 = a31 * 229 + a30 * 228 + ... ... u >> 29 = a31 * 22 + a29 * 21 + ... u >> 30 = a31 * 21 + a30 * 20 u >> 31 = a31 * 20
我们将通过以下公式计算比特数:
u >> 0 - u >> 1 - u >> 2 - ... - u >> 31 = p
让我们看看为什么这样有效:
u >> 0 - u >> 1 - u >> 2 - ... - u >> 31
= u >> 0 - (u >> 1 + u >> 2 + ... + u >> 31)
= u - q
q
的价值是多少? 让我们一点一点地计算它,看看上面的u >> k
的值。 对于a 31
,它是:
a31 * 230 + a31 * 229 + ... = a31 * (230 + 229 + ...) = a31 * (231 - 1)
或者a 30
:
a30 * 229 + a30 * 228 + ... = a30 * (229 + 228 + ...) = a30 * (230 - 1)
我们发现: q = a 31 * (2 31 - 1) + a 30 * (2 30 - 1) + ...
因此
u - q = a31 * 231 - a31 * (231 - 1) + ... = a31 + a30 + ... + a0
这个算法从做同样的事情开始,但是以3比特的块为单位:
u >> 0 = AaBbbCccDddEeeFffGggHhhIiiJjjKkk (each letter is a bit)
u >> 1 & 033333333333 = A Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk (blank = zero)
u >> 2 & 011111111111 = B C D E F G H I J K
根据这些差异,通过上述算法, uCount
中的每个八位字节包含在u
相应八位字节中设置的位数。
uCount = αβγδεζηθικλ (each greek letter is an octet)
uCount >> 3 = αβγδεζηθικ
所以uCount + (uCount >> 3)
是(λ+κ) * 2 0 + (κ+ι) * 2 3 + (ι+θ) * 2 6 + ...
通过与0o30707070707
,我们屏蔽掉每隔一个八位字节,这样我们只计算每对一次:
r = (λ+κ) * 20 + (ι+θ) * 26 + (η+ζ) * 212 + ... = (λ+κ) * 640 + (ι+θ) * 641 + (η+ζ) * 642 + ...
这是一个base-64数,我们想总结基数为64的数字得到α+β+γ+δ+ε+ζ+η+θ+ι+κ+λ
,这是我们的最终结果。 为此,我们计算其base-64 数字根 :知道结果永远不会大于32,我们只需将数字模数为63。
因此,检查一位掩码并针对目标值中的每个位移位的解决方案实际上是O(1)
(例如,其中常数是32)。
最快的方法是使用popcnt指令。 您通常可以通过编译器内部访问它。 您的解决方案在缺少此指令的平台上非常有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.