Java LeetCode 231:查找给定数字是否为2的幂的问题
我想用数学的方法,而不是按位的方法,来确定一个给定的数字是否是a。这是我的密码:Java LeetCode 231:查找给定数字是否为2的幂的问题,java,algorithm,math,Java,Algorithm,Math,我想用数学的方法,而不是按位的方法,来确定一个给定的数字是否是a。这是我的密码: private static double logBaseTwo(final double x) { return Math.log(x) / Math.log(2); } private static double roundToNearestHundredThousandth(final double x) { return Math.round(x * 100000.0) / 100000.
private static double logBaseTwo(final double x) {
return Math.log(x) / Math.log(2);
}
private static double roundToNearestHundredThousandth(final double x) {
return Math.round(x * 100000.0) / 100000.0;
}
private static boolean isInteger(final double x) {
return (int)(Math.ceil(x)) == (int)(Math.floor(x));
}
public static boolean isPowerOfTwo(final int n) {
return isInteger(roundToNearestHundredThousandth(logBaseTwo(n)));
}
对于某些数字,例如
524287
,它错误地返回true
。为什么会这样?这是一段非常糟糕的代码,我不知道你想做什么。您似乎试图检查n
的log
base2
是否为整数。相反,我将编写一个循环:
while (n>1) {
m = (n/2) * 2
if (n!=m){
return false;
}
n /=2;
}
return true;
解决方案似乎比应该的复杂。我没有得到
100000d
零件-在转换到天花板时可能会导致问题
这是适用于所有情况的简单解决方案:
public静态布尔值isPowerOfTwo(int n){
返回Math.ceil(Math.log(n)/Math.log(2))==Math.floor(Math.log(n)/Math.log(2));
}
双精度和浮点数分别具有64位和32位精度。这意味着他们最多只能持有18446744073709551616个唯一的号码。这是很多数字,但不是无限的。在某一点上(事实上,该点大约发生在2^52),作为18446744073709551616可表示数字的一部分的任何两个数字之间的“间隙”将大于1.000。类似的规则也适用于小数字。Math.log不执行基于的双重数学
其次,INT也同样有限。它们最多可以容纳4294967296个不同的号码。对于整数来说,它要简单得多:整数可以从-2147483648保存到2147483647。如果您尝试将1添加到2147483647中,您将得到-2147483648(它会自动环绕)。很有可能你在尝试将如此大的数字(你的两倍乘以10000d)先转换成整数时遇到了这种情况
请注意,?true:false(与问题的原始版本一样)实际上是完全无用的。问号左边的东西必须是布尔值,布尔值已经是真或假了,这就是它们的本质
有关解决此问题的更简单方法,请参见其他答案。当然,最简单的解决方案是简单地计算数字中的位。如果正好是1位,则是2的幂。如果它是0位,那么,你告诉我,如果你认为“0”是一个2的幂:最初我在计算中使用了<代码>数学> log < /代码>。我切换到Math.log10
,问题就解决了。尽管从数学上讲,基B的任何logB
都应该可以工作,但浮点数学的性质可能是不可预测的
试试这个
public static boolean isPowerOfTwo(int n) {
return n > 0 && Integer.highestOneBit(n) == Integer.lowestOneBit(n);
}
如果你喜欢使用日志,你可以这样做
public static boolean isPowerOfTwo(int n) {
return n > 0 && (Math.log10(n)/Math.log10(2))%1 == 0;
}
您的代码失败,因为您可能需要更高的精度来捕获BIG_NUMBER和BIG_NUMBER+1日志之间的差异
按位方式确实是最好的,但如果您真的只想使用“mathy”运算,那么您最好的方法可能是:
public static boolean isPowerOfTwo(final int n) {
int exp = (int)Math.round(logBaseTwo(n));
int test = (int)Math.round(Math.pow(2.0,exp));
return test == n;
}
此解决方案不需要任何超精细精度,适用于所有正整数。我希望您认识到,使用逐位方法是一种数学方法。他们认为你建议的方式过于复杂,在计算机上工作有困难。@ruakh编辑问题使答案无效是错误的。请把三元运算符放回去。@NomadMaker:问题是为什么代码不起作用。正如rzwitserloot所指出的,三元运算符不影响代码的行为;所以这与问题无关。@ruakh它混淆了对答案的理解。它应该留在问题中,或者在问题中添加一条注释,说明原始代码(…)已被此代码(…)替换。@NomadMaker:我现在编辑了该答案,以澄清它所指的内容。+1。精确到十万分之一正是问题所在:log₂ 524287≈ 18.999997正在四舍五入到19.0,这是一个整数。因此,在某种意义上,OP的代码是524287到524288的四舍五入,这是二的幂。(顺便说一句,欢迎使用堆栈溢出!)事实上,很抱歉,这个答案是不正确的:这段代码错误地为536870912
(至少在我的系统上)返回false
,因为浮点结果是29.00000000000000 4
,而不是29
。这是我的错误,我不确定我是如何忽略它的。使用Math.log并没有消除数学错误,所以我切换到Math.log10,它成功了。这仍然困扰着我,因为在分子和分母中使用任何基的log
。但这是数学,我们正在使用IEEE754,因此即使使用ceil和floor方法也无法消除计算中的微小误差。