检查整数中是否 0 (零)的最佳方法是什么
例如:
505 -> True
555 -> False
44444032 -> True
0000 -> True
我试过这个
public bool has0(int no)
{
if(no==0)return true;
while(no!=0)
{
if(no%10==0)return true;
no=no/10;
}
return false;
}
这很有效,但考虑到我需要在大数字上特别称这种方法 10亿次,这需要特别花费大量时间
for(int i=0;i<1000000000;i++)has0(i);
那么,通过使用|
,&
,^
或其他任何方式使用某些位级运算符来检查数字中是否存在0的最佳方法是什么。
谢谢..
答案 0 :(得分:8)
模数是一种昂贵的整数运算(类似于整数除法)。您可以通过查看数字是否均匀来消除测试中一半可能的答案。没有奇数的模10等于零。
if(((no&amp; 0x1)== 0x00)&amp;&amp;((no%10)== 0)) return true;
你会在偶数上付出更多,但在奇数上却少得多。因此,如果它是所有偶数,这将无济于事(它实际上会受到伤害),但如果它是50/50甚至20/80(20%奇数),你可能仍会领先。
此外,整数乘法更便宜,因此您可以先进行除法并计算模10。
while (no)
{
if (no & 0x1)) // odd?
no /= 10;
else // even
{
int nNext = no / 10; // just do integer divide, and calculate modulo in next line
if ((no - (10 * nNext)) == 0) // replaces "more expensive" modulo operation with integer multiply and subtraction
return true;
no = nNext;
}
}
答案 1 :(得分:4)
虽然接受的答案肯定比原始代码快,但使用查找表的方法仍然会快得多。
在我的慢速笔记本电脑上,你的原始代码〜28秒用于处理2.5亿个数字,并且用接受到的答案代码约23秒。使用查找表,只需要 7s 。
当您查看代码时,显而易见的原因是:
bool HasZero(int num)
{
if (num < 100000) return lookup[num];
int upperDigits = num / 100000;
int lowerDigits = num - (upperDigits * 100000);
return lookup[upperDigits] || lowerDigits < 10000 || lookup[lowerDigits];
}
代码具有一个除法,一个减法,一个乘法,两个比较和两个数组查找的最大。即使是优化,逐位数字也可能太多。并且预先计算查找表需要花费大量时间(<1ms)。
请注意,如果您不使用32位整数,代码将无法正常工作,因为那时您需要验证第三组数字(或将查找表的大小从10 ^ 5增加到10 ^ 6;我想它仍然会更快。)
答案 2 :(得分:0)
一个小主意。除常数的除法可以用乘法和移位序列代替。如果您使用的编译器或虚拟机有线索,那么它将自己执行此操作。如果它是愚蠢的,你可以通过手动插入乘法和移位序列来获得一些主要的加速。例如,对于Java HotSpot客户端虚拟机,我发现下面的技术(非负n的正确性)是执行除法的明显方式(注释掉)的两倍以上,并且速度快了五倍作为使用modulo的原始循环。
static boolean has0(int n) {
do {
//int divided = n / 10;
int divided = (int)((n * 0xCCCCCCCDL) >>> 35);
if (divided * 10 == n) return true;
n = divided;
} while (n != 0);
return false;
}
但对于Java HotSpot Server虚拟机来说,这种显着的方法已经很快了,而且这个技巧已经很快了,这个技巧也无济于事,甚至让它变慢。不幸的是,通过这种非常低级别的优化,你必须准备好为不同的语言和语言实现重新调整它。
在尝试测量此类内容之前,请先阅读weird and wonderful complexities of microbenchmarking in Java。
答案 3 :(得分:-2)
如果没有== 0,您的函数将返回false。除此之外,我无法看到你如何做得更好。