【问题标题】:Constrained counting sets on binary codes二进制代码上的约束计数集
【发布时间】:2018-11-08 19:04:10
【问题描述】:

问题表述:给定一个长度为 l 的二进制代码,对于每 t 位集合 (l%t=0),如果至少存在一位值为 1 的位,我们将结果加 1。

我的问题:如何有效地得到最终结果?

例如,我们有一个二进制代码010 110 000,并且 t=3。那么最终结果是 2。因为对于000,没有值 1 的位。对于 110,至少存在一位值 1。我们将结果加 1。对于 010,也存在一位值 1。我们将结果加 1。因此,最终结果为 2。

我的问题是如何有效地解决这个问题而不扫描每 t 位,这会导致时间复杂度与二进制代码的长度成线性关系。

对于计数集问题(计算二进制代码中有多少个 1),有一些算法需要恒定时间来解决它,方法是采用有限数量的掩码和移位操作,例如 MIT HAKMEM Count 算法。

但是,传统计数集问题的现有算法无法用于解决我的问题。

有人知道解决我问题的一些技巧吗?如果它使问题更容易解决,您可以假设输入二进制代码的最大长度。

【问题讨论】:

  • 输入的形式是什么?一个字符串?字节数组?
  • 输入的形式并不重要。输入只是一个随机的二进制代码。
  • 形式非常重要。 String 的解决方案与 byte[]intlongBigInteger 值的解决方案没有任何共同之处。
  • 那么对于这个问题,你可以假设输入是一个64位整数的二进制代码。

标签: java algorithm binary


【解决方案1】:

来自comment

那么对于这个问题,你可以假设输入是一个 64 位整数的二进制代码。

这里有两种不同的方法。

第一次运行在 O(I/t) 中并通过测试每个集合的所有 0 位来工作。

public static int countSets(int setSize, long bits) {
    Long mask = (1L << setSize) - 1;
    int count = 0;
    for (long b = bits; b != 0; b >>>= setSize)
        if ((b & mask) != 0)
            count++;
    return count;
}

第二次运行在 O(log I) 中,通过将集合的位折叠到集合的最右边位,然后计算位集合来工作。

public static int countSets(int setSize, int bitCount, long bits) {
    long b = bits, mask = 1;
    for (int i = 1; i < setSize; i++)
        b |= bits >>> i;
    for (int i = setSize; i < bitCount; i <<= 1)
        mask |= mask << i;
    return Long.bitCount(b & mask);
}

进一步说明

第一种方法为集合构建掩码,例如使用t = 3,掩码为111

然后将值向右移动,t 位一次,例如使用input = 010 110 000t = 3,你会得到:

mask = 111
b = 010 110 000  ->  b & mask = 000  ->  don't count
b =     010 110  ->  b & mask = 110  ->  count
b =         010  ->  b & mask = 010  ->  count
result: 2

第二种方法首先将位合并到集合的最右边位,例如使用input = 010 110 000t = 3,你会得到:

bits      = 010 110 000
bits >> 1 = 001 011 000
bits >> 2 = 000 101 100
b (OR'd)  = 011 111 100

然后它构建一个仅检查最右边位的掩码,然后应用掩码并对设置的位进行计数:

mask     = 001 001 001
b & mask = 001 001 000
result: 2

【讨论】:

  • 优秀的“希腊”比特学! (+1)
  • 感谢您的回复。我昨天自己想出了一个解决方案,与您的第二个解决方案几乎相同。唯一的区别是时间复杂度分析。在我看来,如果机器是 64 位或更高的系统,它应该是 O(t),这意味着任何按位运算都需要恒定的时间。对于第一个“for”循环,它需要 O(t) 时间。对于第二个“for”循环,我们可以通过简单地将掩码指定为八进制 0111 来避免此循环。
  • 在我们应用方程'b&mask'后,我们可以使用现有的方法,如MIT HAKMEM来计算位集,这需要恒定的时间。因此,总复杂度应该是 O(t)。如果我错了,请纠正我。
  • @EricHuang 您不能将掩码指定为八进制 0111。第二个版本要求掩码为 ...1000100010001,1 位之间的距离由 t 确定。 --- 你谈论 MIT HAKMEM 来计算位数。你认为Long.bitCount() 做了什么?请参阅 Long 的 javadoc:“bit twiddling”方法(例如 highestOneBitnumberOfTrailingZeros)的实现基于 Henry S. Warren, Jr. 的 Hacker's Delight,(艾迪生韦斯利,2002 年)。
猜你喜欢
  • 1970-01-01
  • 2013-05-17
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多