我想测试一个正整数,看看它的二进制表示是从0开始还是1开始,后跟一个或多个0。
00000000 // Valid
10000000 // Valid
11000000 // Valid
11100000 // Valid
11110000 // Valid
11111100 // Valid
11111110 // Valid
11111110 // Valid
11111111 // Not Valid
// Any other combination is Not Valid
表达为正则表达式的是^ [1] * [0] + $。当然这只是为了澄清,我们不能使用正则表达式。
蛮力接近:
问题是我正在处理可能有数十万个数字的巨大正整数,需要对数千个这样的数字执行此测试。
有没有更有效的方法来确定这种二元模式?
更新
这是我尝试过的实现。尚未将时间与其他答案进行比较。
public static bool IsDiagonalToPowerOfTwo (this System.Numerics.BigInteger number)
{
byte [] bytes = null;
bool moreOnesPossible = true;
if (number == 0) // 00000000
{
return (true); // All bits are zero.
}
else
{
bytes = number.ToByteArray();
if ((bytes [bytes.Length - 1] & 1) == 1)
{
return (false);
}
else
{
for (byte b=0; b < bytes.Length; b++)
{
if (moreOnesPossible)
{
if (bytes [b] == 255)
{
// Continue.
}
else if
(
((bytes [b] & 128) == 128) // 10000000
|| ((bytes [b] & 192) == 192) // 11000000
|| ((bytes [b] & 224) == 224) // 11100000
|| ((bytes [b] & 240) == 240) // 11110000
|| ((bytes [b] & 248) == 248) // 11111000
|| ((bytes [b] & 252) == 252) // 11111100
|| ((bytes [b] & 254) == 254) // 11111110
)
{
moreOnesPossible = false;
}
else
{
return (false);
}
}
else
{
if (bytes [b] > 0)
{
return (false);
}
}
}
}
}
return (true);
}
答案 0 :(得分:3)
假设整数以二进制形式存储,分组为无符号整数的数组x [],您可以这样做:
Define UINT to be the unsigned integer type you are using for the grouped bits.
Define UMAX to be the maximum value of that type (all bits are on).
// Find first word that has a zero bit.
int i;
for (i = highest word in x; 0 <= i; --i)
if (x[i] != UMAX)
break;
// Return true if all bits in all of x[] are on.
if (i < 0)
return true;
// Test whether word conforms to the ones-then-zeroes rule.
UINT y = x[i];
if (y + (y & -y))
return false;
// Test whether all remaining words are zero.
for (; 0 <= i; --i)
if (x[i])
return false;
return true;
在y + (y & -y)
中,y & -y
返回y中设置的最低位。 (证据留给读者练习。)如果y中的所有高位都打开,则添加最低位会使进位传播所有这些位,将它们更改为零。如果任何高位都关闭,则进位停止,结果不为零。否则,结果为零。
你能改善上述情况吗?假设比较和分支的成本高于AND等操作。在这种情况下,您可以使用二进制搜索来查找数组中的位置,其中值从全部变为全零或两者都不变。测试上面标识的关键词,然后将所有较高的值一起测试并测试所有较高值的结果,然后将所有较低值的OR一起测试,并测试所有零的结果。
它为您提供二进制搜索,后跟一个加载,每个单词一个AND或OR。这很难改进。
答案 1 :(得分:1)
在最坏的情况下,如果没有关于存储输入的附加数据,你不能比O( n )算法做得更好 - 其中 n 是比特数 - 因为你需要检查数字中的每一位。
如果您可以跟踪例如在之前的操作过程中,“最右边1”和“最左边0”,你可以通过检查这些是否确实是“10”来立即获得答案。
否则,您只需要有效地迭代这些位来检查它是否正确。请注意,从左侧开始数字直到达到1,然后检查所有内容为0(使用适当的边角情况)为O( n ),而具有O的完整列表( n )可能的值并检查它是否相等(大概是?)O( n )比较中的任何一个是O( n ^ 2)因此是一个坏主意。
答案 2 :(得分:0)
将二进制数据划分为固定大小的块... 32位... 64位 - &gt;将它们视为无符号整数
准备两个包含所有有效模式的哈希映射,以及反模式(以'0'开头,以'1'结尾)...再次无符号整数
现在测试最左边的块是否包含在逆模式hashmap中...如果不包含 - &gt;模式无效
现在测试正常模式hashmap中是否包含最右边(非零)块...如果不包含 - &gt;模式无效
现在测试所有其他块是否等于所有位设置模式(应该是与无符号整数的比较)...如果全部相等 - >模式有效...其他...模式无效