问题公式:给定长度为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算法)来获取恒定时间来解决它。
但是,传统计数集问题的现有算法不能用于解决我的问题。
有谁知道我的问题的一些技巧?如果使问题更容易解决,您可以假设输入二进制代码的最大长度。
答案 0 :(得分:2)
来自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 000
和t = 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 000
和t = 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