给定一个大小为N的数字S。对S的所有子集进行计数,这些子集对子集元素的累积XOR小于K。
我可以想到蛮力方法来生成S的所有子集,并对累积XOR元素小于k的子集进行计数。我正在寻找不生成S的所有子集的优化解决方案,我可以找到所有这样的子集
Example:
S = {1,2}
K = 4
U = {{},{1},{2},{1,2}}
Answer is 4 As
cumulative XOR values are 0 for {}, 1 for {1}, 2 for {2}, 3 for {1,2}.
答案 0 :(得分:3)
根据问题的约束,有几种可行的解决方法:
O(2^N)
中的所有可能子集都会产生预期的结果。让我们看一下S中数字的二进制表示形式,例如对于数字17、5、20、14,它将是:
10001 17
00101 5
10100 20
01110 14
与K相同,例如,让K = 11:
01011 11
如果我们要计算多少个XOR精确地等于 K,我们可以将问题表示为模2的线性方程组,其变量与S中的数字一样多,并且许多方程式,因为我们的数字中包含有意义的位。更具体地,让第i个方程式表示约束“ S的子集中的数字的第i个比特的XOR应等于K中的第i个比特”。 (请注意,“异或”运算等效于求和模2)。例如,对于最小(最右边)位,我们具有以下内容:x1 * 1 + x2 * 1 + x3 * 0 + x4 * 0 = 1 (mod 2)
,其中x_j为0或1,具体取决于我们是否在子集中包含第j个数字。
请注意,此方程组可能具有0、1或许多解。对于许多解,每个自变量可以取0或1,因此解的数量为2 ^(独立变量)。
我们可以使用高斯消除来检测线性方程组的独立变量和可解性,该高斯消除在O(n^3)
中针对大小为n
的方阵运行-在您的情况下,矩阵为' t平方,因此我们可以使用(|S|, log(max(S))
中的较大者来估算复杂度。
太好了,现在我们可以遍历所有K'从0到K-1
,分别解决问题,并对结果求和。但是,这没有比动态编程解决方案更好的地方,并且在运行时只是伪多项式。让我们再做一个观察,得出多项式解:我们只对O(logK)
个不同的方程组感兴趣,以计算多少个XOR子集小于K
。
让我们将K
中最高的非零位表示为B。如果在我们采用的子集的XOR中,高于B的所有位以及位B都等于0,那么显然小于K
。因此,我们的第一个方程组只能写为上述位,而忽略B以下的所有内容。
现在让我们看看如果我们允许第B位等于1,会发生什么情况。如果在数字K
中,在第B位之后有一个或多个零位,它们都必须为0在产生的XOR中也是如此。如果在我们的XOR中将第一个后续的非零位B2设置为0,那么它将小于K。我们可以通过说“ B之上的所有位均为0,B为1,B和B2之间的所有位均为0,B2为0“,并计算解决方案的数量。
如果我们继续这样操作,直到K
中最小的二进制位置,我们将最多需要建立logK
方程组,并获得所需的结果。
这种方法的复杂性类似于O(logK * max(n, logK)^3)
,尽管根据实现的不同,高斯消去法对于非平方矩阵的工作要快得多。
答案 1 :(得分:0)
问题与count of subsets having sum equal to k非常相似。 我们可以以类似的方式进行,求和的总和等于0到k。
下面是我的python实现。
它使用动态编程将一些中间结果存储在DP表的每个单元格中。单元格dp [i] [j]包含等于j
的子集数量,可以使用排序数组中的前ith
个数字形成子集。
时间复杂度O(n * maxXor)
,其中maxXor
是maximum value which can be achieved by xoring any of the numbers in the array
。 maxXor
的最大值等于maxValue present in array
和K
from math import floor, log
arr = [1, 2]
K = 4
def getCoundDp(arr, k):
arr.sort()
maxVal = arr[-1]
maxXor = 2**(floor(log(max(maxVal, k), 2)) + 1)
dp = [[0 for i in range(maxXor)] for a in arr]
dp[0][0] = 1
# in the 1st row, mark the arr[0] to have count 1
dp[0][arr[0]] = 1
for row in range(1, len(arr)):
for col in range(maxXor):
dp[row][col] += dp[row-1][col]
neededXor = col ^ arr[row]
dp[row][col] += dp[row-1][neededXor]
return sum(dp[-1][:k])
print(getCoundDp(arr, K))
您关于生成和检查所有子集的建议将非常缓慢O(2^n)
。但是至少应该对验证更快的实现有价值。以下是使用itertools.combination
的python中的蛮力方法示例,您可以详细了解here。
from itertools import combinations
def getXor(arr):
xor = 0
for i in arr:
xor ^= i
return xor
def getCountBruteForce(arr, k):
arr.sort()
countLessThanK = 0
for r in range(0, len(arr)+1):
for comb in combinations(arr, r):
xor = getXor(comb)
if xor < k:
countLessThanK += 1
return(countLessThanK)