一个数组的 异或总和 定义为数组中所有元素按位 XOR
的结果;如果数组为 空 ,则异或总和为 0
。
- 例如,数组
[2,5,6]
的 异或总和 为2 XOR 5 XOR 6 = 1
。
给你一个数组 nums
,请你求出 nums
中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。
注意:在本题中,元素 相同 的不同子集应 多次 计数。
数组 a
是数组 b
的一个 子集 的前提条件是:从 b
删除几个(也可能不删除)元素能够得到 a
。
示例 1:
输入:nums = [1,3] 输出:6 解释:[1,3] 共有 4 个子集: - 空子集的异或总和是 0 。 - [1] 的异或总和为 1 。 - [3] 的异或总和为 3 。 - [1,3] 的异或总和为 1 XOR 3 = 2 。 0 + 1 + 3 + 2 = 6
示例 2:
输入:nums = [5,1,6] 输出:28 解释:[5,1,6] 共有 8 个子集: - 空子集的异或总和是 0 。 - [5] 的异或总和为 5 。 - [1] 的异或总和为 1 。 - [6] 的异或总和为 6 。 - [5,1] 的异或总和为 5 XOR 1 = 4 。 - [5,6] 的异或总和为 5 XOR 6 = 3 。 - [1,6] 的异或总和为 1 XOR 6 = 7 。 - [5,1,6] 的异或总和为 5 XOR 1 XOR 6 = 2 。 0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28
示例 3:
输入:nums = [3,4,5,6,7,8] 输出:480 解释:每个子集的全部异或总和值之和为 480 。
from typing import List
class Solution:
def subsetXORSum(self, nums: List[int]) -> int:
total_sum = 0
n = len(nums)
# 2^n possible subsets
for i in range(1 << n):
xor_sum = 0
for j in range(n):
if i & (1 << j):
xor_sum ^= nums[j]
total_sum += xor_sum
return total_sum
1 << n
的意义:
1 << n
是位移运算,用于生成2^n
。在这里,n
是数组nums
的长度。位移运算1 << n
会将数字1
向左移动n
位,结果是2^n
。例如,如果n = 3
,那么1 << 3
就是8
,即2^3
。
for i in range(1 << n):
这个循环遍历了所有可能的子集。1 << n
是2^n
,所以i
从0
到2^n - 1
,每个i
表示一个不同的子集。
xor_sum = 0
初始化xor_sum
变量,用于存储当前子集的异或和。
for j in range(n):
遍历数组中的每个元素。
if i & (1 << j):
这个条件检查i
的第j
位是否为1
。如果是,说明当前子集包含第j
个元素。
xor_sum ^= nums[j]
将当前元素的值与xor_sum
进行异或操作。异或是累积的,表示当前子集的异或和。
total_sum += xor_sum
将当前子集的异或和加到total_sum
中,累加所有子集的异或和
例子
假设
nums = [1, 2, 3]
,我们来看一下i = 5
时的情况:
转换
i
为二进制:
i = 5
,二进制是101
。检查每一位:
- 对于
j = 0
:
1 << 0
是0001
(即1
)。i & (1 << 0)
是101 & 001
,结果是001
。结果不为0
,所以第0
位为1
,我们选择了nums[0]
(即1
)。- 对于
j = 1
:
1 << 1
是0010
(即2
)。i & (1 << 1)
是101 & 010
,结果是000
。结果为0
,所以第1
位为0
,我们没有选择nums[1]
(即2
)。- 对于
j = 2
:
1 << 2
是0100
(即4
)。i & (1 << 2)
是101 & 100
,结果是100
。结果不为0
,所以第2
位为1
,我们选择了nums[2]
(即3
)。计算异或和:
- 所以
i = 5
选择了nums[0]
和nums[2]
,即[1, 3]
。xor_sum
的计算是1 ^ 3
,结果是2
。