给定范围[a,b](包括两者)我需要找到最小数字,其中二进制表示的最大数量为1。我目前的方法是找到从a到b的所有数字中设置的位数,并跟踪最大值。 然而,这是非常慢的,任何更快的方法?
答案 0 :(得分:2)
让我们找到a和b中不同的最重要的位。它将是0 in a,1 in b。如果我们将右边的所有其他位置于1 - 结果数字仍然在范围内[a; B]。它将是表示最大数量为1的单个数字。
修改即可。该算法的结果总是返回n-1位设置为1的数字,其中n是可以改变的位数。正如评论中所指出的 - 如果b中的所有n位都设置为1,则存在一个错误。这是固定的代码片段:
int maximizeBits(int a, int b) {
if (a == b) {
return a;
}
int m = a ^ b, pow2 = 1; // MSB of m=a^b is bit that we need to find
while (m > pow2) { // Set other bits to 0
if ((m & pow2) != 0) {
m ^= pow2;
}
pow2 <<= 1;
}
int res = a | (m - 1); // Now m is in form of 2^n and m - 1 would be mask of n-1 bits
if ((res | b) <= b) { // Fix of problem if all n bits in b are set to 1
res = b;
}
return res;
}
答案 1 :(得分:2)
你可以用Jarlax&#39;替换循环。通过&#34;并行后缀OR&#34;回答,像这样
uint32_t m = (a ^ b) >> 1;
m |= m >> 1;
m |= m >> 2;
m |= m >> 4;
m |= m >> 8;
m |= m >> 16;
uint32_t res = a | m;
if ((res | b) <= b)
res = b;
return res;
它通常使用ceil(log(k))步骤推广到不同大小的整数。初始测试a == b
不是必需的,a ^ b
将为零,因此m
为零,因此无论如何都不会发生任何有趣的事情。
或者,这是一种完全不同的方法:将最低0改为1,直到不再可能为止。
unsigned x = a;
while (x < b) {
unsigned newx = (x + 1) | x; // set lowest 0
if (newx <= b)
x = newx;
else
break;
}
return x;