📅  最后修改于: 2023-12-03 15:06:20.450000             🧑  作者: Mango
给定一个长度为n的二进制字符串S,计算有多少个三元组(i, j, k)满足0≤i<j<k<n,且S[i]、S[j] 和 S[j]、S[k] 的按位与相同。
题目要求的是三个数的按位与相同,我们可以考虑将一个数拆分成二进制表示下的每一位,然后将这些位拆分成若干个集合,满足一个集合中的所有数字的二进制表示下的1的位置相同。这时,问题就转化成了统计每个集合中的元素之间的三元组个数之和。
如何计算每个集合中的元素的三元组个数呢?考虑将每个集合中的所有元素按位与之后的值进行统计,那么值相同的元素之间构成的三元组的数量就是组合公式C(n, 3)。这里需要注意的是,如果集合中所有元素的二进制表示下的1的数量不足三个,那么对应的组合数为0。同时,如果值相同的元素数量小于三个,那么对应的组合数也为0。
把每个集合内的三元组个数求和即可。
首先需要将每个数字的二进制表示下,1的位置拆分成若干个集合,以便于后续统计。这里可以使用哈希表来实现。
def countTriplets(S: str) -> int:
n = len(S)
cnt = [collections.Counter() for _ in range(16)]
ans = 0
for i in range(n):
c = int(S[i])
cnt[c][0] += 1
for j in range(15):
if (c >> j) & 1:
for k in range(16):
cnt[k][j+1] += cnt[k][j]
for j in range(16):
if cnt[j][j] > 2:
ans += nCr(cnt[j][j], 3)
if cnt[0][0] > 2:
ans += nCr(cnt[0][0], 3)
return ans
对于每个数,先把二进制表示下为0的位的计数器自增1,然后遍历剩下的每个位,如果为1则将这个位的计数器加到其他位上。
最后统计每个集合中的三元组个数即可。
def nCr(n: int, r: int) -> int:
if r > n:
return 0
if r > n // 2:
r = n - r
ans = 1
for i in range(r):
ans *= (n - i)
ans //= (i + 1)
return ans
组合公式的实现。
本题实际上是基于位运算的一个题目。在实现中,需要考虑到时间复杂度和空间复杂度的限制,因此使用了哈希表和组合公式等数据结构和算法来优化程序性能。