[英]How to find number of tuples whose sum is equal or less than a given number?
[英]How to find the largest power of 2 less than the given number
我需要找到小于给定数字的 2 的最大幂。
我卡住了,找不到任何解决方案。
代码:
public class MathPow {
public int largestPowerOf2 (int n) {
int res = 2;
while (res < n) {
res =(int) Math.pow(res, 2);
}
return res;
}
}
这不能正常工作。
测试输出:
Arguments Actual Expected
-------------------------
9 16 8
100 256 64
1000 65536 512
64 256 32
如何解决这个问题?
Integer.highestOneBit(n-1);
对于n <= 1
这个问题没有意义。 在该范围内做什么由感兴趣的读者决定。
这是Hacker's Delight中一些很好的 bit twiddling 算法集合。
更改res =(int)Math.pow(res, 2);
到res *= 2;
这将返回大于 res 的下一个 2 的幂。
因此,在一段时间结束后,您正在寻找的最终结果最终将是res / 2
。
为了防止代码溢出 int 值空间,您应该/可以将 res 的类型更改为 double/long,任何可以保存比 int 值更高的值。 最后,您将不得不施放一次。
你可以使用这个小技巧:
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
v >>= 1;
为什么不使用日志?
public int largestPowerOf2(int n) {
return (int)Math.pow(2, Math.floor(Math.log(n) / Math.log(2));
}
log(n) / log(2)
告诉你 2 进入一个数字的次数。 通过使用它,您可以得到四舍五入的整数值。
Integer
中有一个很好的函数numberOfLeadingZeros
很有帮助。
有了它你可以做到
0x80000000 >>> Integer.numberOfLeadingZeros(n - 1);
当n
为 0 或 1 时,这会做一些奇怪的事情,但是对于这些输入,没有明确定义的“小于n
的 2 的最大幂”。
编辑:这个答案更好
您可以消除 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;
}
}
解释:
当您有一个数字 n(不是 2 的幂)时,小于 n 的最大 2 幂始终是 n 中的最高有效位。 如果数字 n 是 2 的幂,则小于 n 的最大 2 幂是 n 中唯一打开的位之前的位。
例如,如果我们有 8(2 的 3 次方),它的二进制表示是 1 0 00 粗体的 0 将是 n 之前 2 的最大幂。 既然我们知道二进制中的每个数字都代表 2 的幂,那么如果我们将 n 作为一个 2 的幂的数字,那么小于 n 的 2 的最大幂将是它之前的 2 的幂,这将是位在 n 中的唯一位之前。
对于一个不是 2 的幂也不是 0 的数字 n,我们知道在二进制表示中 n 会有不同的位,这些位只代表 2 的各种幂的和,其中最重要的是成为最重要的位。 然后我们可以推断出 n 只是最高有效位加上一些其他位。 由于 n 以一定长度的位表示,并且最高有效位是我们可以用该位数表示的 2 的最高幂,但它也是我们可以用那么多位表示的最低数,那么我们可以得出结论最高有效位是小于 n 的 2 的最高幂,因为如果我们添加另一个位来表示下一个 2 的幂,我们将有一个大于 n 的 2 幂。
例子:
例如,如果我们有 168(二进制为 10101000),while 将取 168 并减去 1,即 167(二进制为 10100111)。 然后我们将对两个数字进行按位与运算。 例子:
10101000
& 10100111
------------
10100000
我们现在有二进制数 10100000。如果我们从它减去 1 并对两个数字使用按位与,我们得到 10000000,即 128,即 2 的 7 次方。
例子:
10100000
& 10011111
-------------
10000000
如果 n 原本是 2 的幂,那么我们必须从 n 中减去 1。 例如,如果 n 是 16,即二进制的 10000,我们将减去 1,得到 15,即二进制的 1111,然后将其存储在 n 中(这就是 if 的作用)。 然后我们进入 while ,它对 n 和 n-1 执行按位运算符 AND,这将是 15(二进制 1111)和 14(二进制 1110)。
例子:
1111
& 1110
--------
1110
现在剩下 14。然后我们对 n 和 n-1 执行按位与运算,即 14(二进制 1110)和 13(二进制 1101)。
例子:
1110
& 1101
---------
1100
现在我们有 12 个,我们只需要消除最后一个最低有效位。 再次,我们然后对 n 和 n-1 执行按位 AND,即 12(二进制 1100)和 11(二进制 1011)。
例子
1100
& 1011
--------
1000
我们最终剩下 8,这是 2 小于 16 的最大幂。
您每次都对res进行平方,这意味着您计算2^2^2^2
而不是2^k
。
将您的评估更改为以下内容:
int res = 2;
while (res * 2 < n) {
res *= 2;
}
更新:
当然,你需要检查int 的溢出,在这种情况下检查
而 (res <= (n - 1) / 2)
似乎好多了。
public class MathPow {
public int largestPowerOf2 (int n) {
int res = 2;
while (res < n) {
res = res * 2;
}
return res;
}
}
这是我为此目的编写的递归位移方法:
public static int nextPowDown(int x, int z) {
if (x == 1)
return z;
return nextPowDown(x >> 1, z << 1);
}
或更短的定义:
public static int nextPowTailRec(int x) {
return x <= 2 ? x : nextPowTailRec(x >> 1) << 1;
}
因此,在您的 main 方法中,让z
参数始终等于1
。 可惜这里没有默认参数:
System.out.println(nextPowDown(60, 1)); // prints 32
System.out.println(nextPowDown(24412, 1)); // prints 16384
System.out.println(nextPowDown(Integer.MAX_VALUE, 1)); // prints 1073741824
有点晚了但是...
(假设 32 位数字。)
n|=(n>>1);
n|=(n>>2);
n|=(n>>4);
n|=(n>>8);
n|=(n>>16);
n=n^(n>>1);
解释:
第一 | 确保设置了原始最高位和第二高最高位。 第二 | 确保这两个,接下来的两个是,等等,直到你可能达到所有 32 位。 IE
100010101 -> 111111111
然后我们通过将 1 的字符串与该 1 的字符串向左移动 1 进行异或运算来移除除最高位之外的所有位,最后我们只得到最高位后跟 0 的一位。
从左到右找到第一个设置位,并使所有其他设置位为 0。
如果只有 1 个设置位,则右移一位。
我认为这是最简单的方法。
Integer.highestOneBit(n-1);
public class MathPow
{
public int largestPowerOf2(int n)
{
int res = 1;
while (res <= (n-1)/2)
{
res = res * 2;
}
return res;
}
}
如果数字是整数,您可以随时将其更改为二进制,然后找出位数。
n = (x>>>0).toString(2).length-1
p=2;
while(p<=n)
{
p=2*p;
}
p=p/2;
如果数字是 2 的幂,那么答案是显而易见的。 (只是位移)如果不好,那么也可以通过位移来实现。
以二进制表示找到给定数字的长度。 (二进制 13 = 1101 ;长度为 4)
then shift 2 by (4-2) // 4 是给定数字的二进制长度
下面的 java 代码将为 BigIntegers 解决这个问题(所以基本上适用于所有数字)。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String num = br.readLine();
BigInteger in = new BigInteger(num);
String temp = in.toString(2);
System.out.println(new BigInteger("2").shiftLeft(temp.length() - 2));
我在上面看到了另一个 BigInteger 解决方案,但这实际上很慢。 如果我们要超越整数和长,更有效的方法是
BigInteger nvalue = TWO.pow(BigIntegerMath.log2(value, RoundingMode.FLOOR));
其中TWO
只是BigInteger.valueOf(2L)
BigIntegerMath
取自番石榴。
简单的位操作应该可以工作
public long largestPowerOf2 (long n)
{
//check already power of two? if yes simply left shift
if((num &(num-1))==0){
return num>>1;
}
// assuming long can take 64 bits
for(int bits = 63; bits >= 0; bits--) {
if((num & (1<<bits)) != 0){
return (1<<bits);
}
}
// unable to find any power of 2
return 0;
}
/**
* Find the number of bits for a given number. Let it be 'k'.
* So the answer will be 2^k.
*/
public class Problem010 {
public static void highestPowerOf2(int n) {
System.out.print("The highest power of 2 less than or equal to " + n + " is ");
int k = 0;
while(n != 0) {
n = n / 2;
k++;
}
System.out.println(Math.pow(2, k - 1) + "\n");
}
public static void main(String[] args) {
highestPowerOf2(10);
highestPowerOf2(19);
highestPowerOf2(32);
}
}
if(number>=2){
while(result < number){
result *=2;
}
result = result/ 2;
System.out.println(result);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.