【问题标题】:Smallest number in a range [a,b] with maximum number of '1' in binary representation范围 [a,b] 中的最小数字,二进制表示中的最大数字为“1”
【发布时间】:2015-01-12 17:11:13
【问题描述】:

给定一个范围 [a,b](包括),我需要找到二进制表示中 '1' 的最大数量的最小数字。我目前的方法是找到从 a 到 b 的所有数字中设置的位数并跟踪最大值。 但是这很慢,有更快的方法吗?

【问题讨论】:

  • 你试过累积x^2吗?我从来没有做过统计和模式数学,但听起来它是相关的......在那个笔记上,不确定这或多或少与数学交换有关
  • 如果你必须在 1000 到 10000 之间找到最多 9 的数字,你不会从 1000 循环到 10000 并计算每个数字中的 9,对吗?
  • 不,但是二进制更难,因为它只由 0 和 1 组成
  • 我意识到我的答案不正确,删除它。

标签: algorithm bit-manipulation


【解决方案1】:

让我们找出在 a 和 b 中不同的最高有效位。它将在 a 中为 0,在 b 中为 1。如果我们将所有其他位放在 1 的右侧 - 结果数字仍将在范围 [a;乙]。它将代表最大数量的单个数字。

编辑。该算法的结果总是返回 n-1 位设置为 1 的数字,其中 n 是可以更改的位数。正如 cmets 中所指出的 - 如果 b 中的所有 n 位都设置为 1,则会出现错误。这是固定代码 sn-p:

int maximizeBits(int a, int b) {
    if (a == b) {
        return a;
    }
    int m = a ^ b, pow2 = 1; // MSB of m=a^b is bit that we need to find
    while (m > pow2) { // Set other bits to 0
        if ((m & pow2) != 0) {
            m ^= pow2;
        }
        pow2 <<= 1;
    }

    int res = a | (m - 1); // Now m is in form of 2^n and m - 1 would be mask of n-1 bits
    if ((res | b) <= b) { // Fix of problem if all n bits in b are set to 1
        res = b;
    }
    return res;
}

【讨论】:

    【解决方案2】:

    您可以将 Jarlax 答案中的循环替换为“并行后缀 OR”,如下所示

    uint32_t m = (a ^ b) >> 1;
    m |= m >> 1;
    m |= m >> 2;
    m |= m >> 4;
    m |= m >> 8;
    m |= m >> 16;
    uint32_t res = a | m;
    if ((res | b) <= b)
        res = b;
    return res;
    

    它概括为不同大小的整数,一般使用 ceil(log(k)) 步骤。初始测试a == b 不是必需的,a ^ b 将为零,因此m 为零,所以无论如何都不会发生任何有趣的事情。


    或者,这是一种完全不同的方法:不断将最低的 0 更改为 1,直到不再可能为止。

    unsigned x = a;
    while (x < b) {
        unsigned newx = (x + 1) | x; // set lowest 0
        if (newx <= b)
            x = newx;
        else
            break;
    }
    return x;
    

    【讨论】:

    • 确实,您的第二个解决方案 while ( (a | (a + 1)) &lt;= b ) { a |= a + 1; } 与我的相同,而且更简单。
    • @Jarlax 等一下!如果b 设置了最大位数怎么办?它不会永远循环吗?
    • 好点,谢谢!我做了一个愚蠢的错误,条件应该是这样的:while (b - (a | (a + 1)) &gt;= 0) { a |= a + 1; }。请注意,它仅适用于有符号整数。对于未签名的您的原始解决方案(我相信)是最简单的。
    猜你喜欢
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    相关资源
    最近更新 更多