如何找到整数(相同数量的 1)的下一个较低二进制数?例如:如果给定输入数 n = 10 (1010),则函数应返回 9 (1001),或者 n = 14 (1110) 然后返回 13 (1101),或者 n = 22 (10110) 然后返回 21 (10101) , n = 25 (11001) 然后返回 22 (10110)... 等等。
问问题
574 次
3 回答
4
你可以这样做。
static int nextLower(int n) {
int bc = Integer.bitCount(n);
for (int i = n - 1; i > 0; i--)
if (Integer.bitCount(i) == bc)
return i;
throw new RuntimeException(n+" is the lowest with a bit count of "+bc);
}
当然,如果这是家庭作业,你将很难说服你写这篇文章的人;)
于 2013-10-19T00:05:49.427 回答
2
为了清楚起见,在这个答案中,我将使用术语“基数”来表示数字二进制表示中 1 的数量。
一种(显而易见的)方法是运行向下循环,并寻找与您的输入具有相同基数的第一个数字(就像 Peter Lawrey 建议的那样)。
我不认为这是低效的,因为我猜输出数字总是非常接近输入。更准确地说,您所要做的就是找到最右边的“10”位序列,并将其更改为“01”。然后将右侧部分替换为左侧全为 1 的数字,在不破坏后置条件的情况下尽可能多地替换。这给我们带来了另一个解决方案,它包括将数字转换为二进制字符串(就像 user2573153 向您展示的那样),执行替换(可能使用正则表达式),然后转换回 int。
下面是彼得算法的一个稍快的版本,它对整数执行我建议你对字符串的操作:
static int nextLower(int n) {
int fixPart = 0;
int shiftCount = 0;
while ((n & 3) != 2) {
if (n == 0) {
throw new IllegalArgumentException(
fixPart + " is the lowest number with its cardinality");
}
fixPart |= (n & 1) << shiftCount;
shiftCount += 1;
n /= 2;
}
int fixZeros = shiftCount - Integer.bitCount(fixPart);
return ((n ^ 3) << shiftCount) | (((1 << shiftCount) - 1) & ~((1 << fixZeros) - 1));
}
这是 O(log n) 而不是 O(n),但由于其复杂性,它肯定更难理解,并且实际上也可能更慢。无论如何,如果您尝试使用一些非常困难的数字,您只会注意到差异。
编辑
我尝试了一个小基准测试,发现当连续应用于从 2 到 100,000,000 的所有数字时,此代码比 Peter Lawrey 的代码快 67% 。我认为这不足以证明增加的代码复杂性是合理的。于 2013-10-19T00:40:45.953 回答
1
我喜欢这样的二进制任务,所以要找到下一个较低的数字,你应该找到最右边的 1,然后是 0 并交换它们。更新:您需要“重新排序”数字的其余部分,左侧为 1,右侧为 0
10 1010 ->
9 1001
14 1110 ->
13 1101
25 11001 ->
22 10110
这是示例代码:
int originalValue = 25;
int maskToCheck = 2; // in binary 10b
int clearingMask = 1;
int settingMask = 0;
int zeroCount = 0;
while (maskToCheck > 0)
{
if ( (originalValue&(maskToCheck|(maskToCheck>>1))) == maskToCheck ) // we found such
{
int newValue = originalValue&(~maskToCheck); // set 1 with 0
newValue = newValue&(~clearingMask)|(settingMask<<zeroCount); // clear all the rest bits, and set most valuable ones
newValue = newValue|(maskToCheck>>1); // set 0 with 1
System.out.println("for " + originalValue + " we found " + newValue);
break;
}
else
{
if ( (originalValue&(maskToCheck>>1)) > 0) // we have 1 bit in cleared part
settingMask = (settingMask<<1) | 1;
else
zeroCount++;
maskToCheck = maskToCheck<<1; // try next left bits
clearingMask = (clearingMask<<1)|1;
}
}
于 2013-10-19T00:10:26.180 回答