📅  最后修改于: 2023-12-03 15:11:40.341000             🧑  作者: Mango
该问题为一个经典的算法问题,题目要求计算给定数组中所有无序对的按位或。
给定一个正整数数组 nums,计算所有满足 i < j 的无序对 (i, j) 的按位或值。
具体地,按位或指每一位都为 0 时为 0,否则为 1。
输入:nums = [5,2,7]
输出:11
解释:所有无序对的按位或值为:
所以答案为 7 | 7 | 7 = 11。
该问题可以使用位运算和线段树两种方法来求解。
对于每一位,若存在两个数在该位上都为 1,则所有的无序对在该位上的按位或值均为 1,反之为 0。
实现时可以将所有数按照二进制位拆分,对于每一位分别进行统计。具体地,使用一个长度为 32 的数组 count 存储每一位上的 1 的个数,然后对于每一个数,统计其二进制中每一位是不是 1,若是则计入 count 数组中,最终遍历所有数,对于每一位上的 1 的个数 count[i],计算出该位上的所有无序对的按位或值为 count[i] * (n - count[i])。
时间复杂度:O(nlogn)
空间复杂度:O(1)
class Solution:
def countPairs(self, nums: List[int]) -> int:
res = 0
for i in range(32):
mask = 1 << i
cnt = 0
for num in nums:
if num & mask:
cnt += 1
res += cnt * (len(nums) - cnt)
return res
线段树的核心思想是将区间分治,将整个区间划分为若干个不相交的子区间,并且用一个树状结构维护这些子区间的信息,以支持区间查询、单点修改等操作。
对于该问题,我们可以将区间按照二进制位上是否相同来分治,具体地,用数组 tree[i][0/1] 表示第 i 位为 0/1 的数的个数,然后对于每一位上的 1,统计在该位上有多少个数是 0,将其与该位上有多少个数是 1 的数相乘,对于所有位上的值求和即为所求。
时间复杂度:O(nlogk),其中 k 为数组中元素的最大值。
空间复杂度:O(nlogk)
class Node:
def __init__(self, l, r):
self.l, self.r = l, r
self.zero, self.one = 0, 0
self.left, self.right = None, None
class SegmentTree:
def __init__(self, nums):
def build(l, r):
if l > r:
return None
node = Node(l, r)
if l == r:
node.zero, node.one = 1, 0 if nums[l] else 1
else:
mid = (l + r) // 2
node.left = build(l, mid)
node.right = build(mid+1, r)
node.zero = node.left.zero + node.right.zero
node.one = node.left.one + node.right.one
return node
self.root = build(0, len(nums)-1)
def query(self, l, r):
def dfs(node):
if not node:
return 0, 0
if node.r < l or node.l > r:
return 0, 0
if l <= node.l and node.r <= r:
return node.zero, node.one
zero1, one1 = dfs(node.left)
zero2, one2 = dfs(node.right)
return zero1+zero2, one1+one2
return dfs(self.root)
class Solution:
def countPairs(self, nums: List[int]) -> int:
st = SegmentTree(nums)
res = 0
for i in range(32):
mask = 1 << i
cnt1, cnt2 = 0, 0
for num in nums:
if num & mask:
cnt1 += 1
else:
cnt2 += 1
num1, num2 = st.query(0, len(nums)-1)
if cnt1 == 0:
res += cnt2 * num2
elif cnt2 == 0:
res += cnt1 * num1
else:
res += cnt1 * num2 + cnt2 * num1
return res//2