如何找到下一个较低的整数(具有相同的1的数量)

时间:2013-10-18 23:47:20

标签: java computer-science

如何为整数(相同数量的1)找到下一个较低的二进制数?例如:如果给定输入数n = 10(1010),则函数应返回9(1001),或n = 14(1110)然后返回13(1101),或n = 22(10110)然后返回21(10101) ,n = 25(11001)然后返回22(10110)......等等。

3 个答案:

答案 0 :(得分:3)

你可以这样做。

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);
}

当然,如果这是家庭作业,你将无法说服你写这篇文章的人;)

答案 1 :(得分:2)

为了清楚起见,在这个答案中,我将使用术语“基数”来表示数字的二进制表示中的1的数量。

一种(显而易见的)方法是运行向下循环,并寻找具有与输入相同基数的第一个数字(就像Peter Lawrey建议的那样)。

我不认为这是低效的,因为我猜输出数总是非常接近输入。更准确地说,您所要做的就是找到最右边的“10”位序列,并将其更改为“01”。然后在不破坏后置条件的情况下,尽可能多地将右侧部分替换为左侧全部为1的数字。这将我们带到另一个解决方案,其中包括将数字转换为二进制字符串(如user2573153显示),执行替换(可能使用正则表达式),然后转换回int。

Peter的算法稍微快一点的版本应该是以下内容,它对整数执行我为字符串提出的操作:

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% 。我不认为这足以证明代码复杂性的增加。

答案 2 :(得分: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;
        }
    }