如何找到比给定数量少2的最大功率

naz*_*art 10 java algorithm

我需要找到比给定数字少2的最大功率.
我卡住了,找不到任何解决方案.

码:

public class MathPow {
   public int largestPowerOf2 (int n) {
        int res = 2;        
        while (res < n) {
            res =(int) Math.pow(res, 2);
        }
        return res;
   }
}
Run Code Online (Sandbox Code Playgroud)

这不能正常工作.

测试输出:

Arguments Actual Expected
-------------------------
9         16     8       
100       256    64      
1000      65536  512     
64        256    32      
Run Code Online (Sandbox Code Playgroud)

如何解决这个问题?

Tom*_*ine 40

Integer.highestOneBit(n-1);
Run Code Online (Sandbox Code Playgroud)

对于n <= 1这个问题并没有多大意义.该范围内的操作留给感兴趣的读者.

这是Hacker's Delight中一个很好的比特算法集合.

  • 这是正确的答案和另一个链接:http://graphics.stanford.edu/~seander/bithacks.html - 没有java,但大多数bit-twiddling也适用于java.和HD是强制性阅读. (2认同)

luk*_*302 11

更改res =(int)Math.pow(res, 2);为此res *= 2;将返回大于res的下一个2的幂.
因此,您正在寻找的最终结果将res / 2在片尾结束后终于出现.

为了防止代码溢出int值空间,你应该/可以将res的类型更改为double/long,任何可以包含比int更高值的值.最后你必须投一次.

  • 我写的除以2. (3认同)
  • 这是接受的答案和大多数投票,而在Integer类中有一个方法(并且它更快) (2认同)

das*_*ght 11

你可以用这个黑客攻击:

v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
v >>= 1;
Run Code Online (Sandbox Code Playgroud)


小智 9

为什么不使用日志?

public int largestPowerOf2(int n) {
    return (int)Math.pow(2, Math.floor(Math.log(n) / Math.log(2));
}
Run Code Online (Sandbox Code Playgroud)

log(n) / log(2)告诉你2进入一个数字的次数.通过采取它的底部,获得四舍五入的整数值.


har*_*old 7

有一个很好的功能,Integer这是有帮助的,numberOfLeadingZeros.

有了它,你可以做到

0x80000000 >>> Integer.numberOfLeadingZeros(n - 1);
Run Code Online (Sandbox Code Playgroud)

n0或1时,哪些奇怪的东西,但对于那些输入,没有明确定义的"2的最大功率小于n".

编辑:这个答案更好


Vyr*_*ral 6

您可以消除n中的最低有效位,直到n为2的幂.您可以使用n和n-1的按位运算符AND,这将消除n中的最低有效位,直到n为2的幂.原来n将是2的幂,那么你所要做的就是将n减少1.

public class MathPow{
   public int largestPowerOf2(int n){
      if((n & n-1) == 0){ //this checks if n is a power of 2
         n--; //Since n is a power of 2 we have to subtract 1
      }
      while((n & n-1) != 0){ //the while will keep on going until n is a power of 2, in which case n will only have 1 bit on which is the maximum power of 2 less than n. You could eliminate the != 0 but just for clarity I left it in
         n = n & n-1; //we will then perform the bitwise operation AND with n and n-1 to eliminate the least significant bit of n 
      }
      return n;
   }
}
Run Code Online (Sandbox Code Playgroud)

说明:

如果你有一个数字n(不是2的幂),那么小于n的最大2的幂总是n中最重要的位.在数n为2的幂的情况下,小于n的2的最大功率是在n中唯一的位之前的位.

例如,如果我们有8(其为2到3次幂),则其二进制表示为1 0 00,粗体0将是n之前的2的最大幂.既然我们知道二进制中的每个数字代表2的幂,那么如果我们将n作为2的幂的数,那么2的最大幂小于n将是2之前的2的幂,这将是位在n中唯一的位之前.

使用数字n,即不是2的幂且不是0,我们知道在二进制表示中n将具有各种比特,这些比特将仅表示2的各种幂的总和,其中最重要的是是最重要的一点.然后我们可以推断出n只是最重要的位加上其他一些位.由于n以一定长度的比特表示,而最高有效位是2的最高功率,我们可以用该比特数表示,但它也是我们用这么多比特表示的最低数,那么我们可以得出结论最高有效位是低于n的2的最高功率,因为​​如果我们添加另一位来表示2的下一个幂,我们将具有大于n的2的幂.

例子:

例如,如果我们有168(二进制为10101000),则while需要168并减去1,即167(二进制为10100111).然后我们将对两个数字进行按位AND. 例:

  10101000
& 10100111
------------
  10100000
Run Code Online (Sandbox Code Playgroud)

我们现在有二进制数10100000.如果我们从它中减1并且我们在两个数字上使用按位AND,我们得到10000000这是128,这是2的7的幂.

例:

  10100000
& 10011111
-------------
  10000000
Run Code Online (Sandbox Code Playgroud)

如果n原来是2的幂,那么我们必须从n中减去1.例如,如果n是16,即二进制10000,我们将减去1,这将留下15,二进制为1111,并将它存储在n(这就是if).然后我们进入while,它使用n和n-1进行按位运算符AND,它将是15(二进制1111)和14(二进制1110).

例:

  1111
& 1110
--------
  1110
Run Code Online (Sandbox Code Playgroud)

现在我们留下14.然后我们用n和n-1执行按位AND,即14(二进制1110)和13(二进制1101).

例:

  1110
& 1101
---------
  1100
Run Code Online (Sandbox Code Playgroud)

现在我们有12个,我们只需要消除最后一个最低位.然后,我们再对n和n-1执行按位AND,即12(二进制1100)和11(二进制1011).

  1100
& 1011
--------
  1000
Run Code Online (Sandbox Code Playgroud)

我们最终留下8,这是2小于16的最大力量.