1863. 找出所有子集的异或总和再求和

这篇博客介绍了如何计算一个数组所有子集的异或总和,并返回这些值的总和。给定一个数组,例如[1,3],通过深度优先搜索(DFS)方法可以计算出所有子集的异或和,然后将它们相加。示例中展示了不同输入数组的计算过程和结果,如[5,1,6]的子集异或和总和为28。该问题涉及到位运算和组合数学的知识。

一个数组的 异或总和 定义为数组中所有元素按位 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 。

C++代码

class Solution {
public:
    int dfs(vector<int> nums, int u){
        int ans = 0;
        
        for(int i = 0; i < (1 << u); i ++){
            int t = 0;
            int j = i;
            for(int k = u - 1; k >= 0; k --){
                if(j >> k & 1) t ^= nums[k];
            }
            ans += t;
        }
        
        return ans;
    }
    
    int subsetXORSum(vector<int>& nums) {
        int n = nums.size();
        return dfs(nums, n);
    }

};
### 异或求和算法实现 异或求和问题的核心是通过运算的性质,优化对所有子集异或和进行计算。以下是基于提供的引用内容以及相关知识的完整解析与实现。 #### 算法思想 1. **异或性质**: - 异或操作具有交换律和结合律。 - 两个相同的数异或结果为0,任何数与0异或结果为其本身。 2. **统计方法**: - 对于每个二进制,统计数组中该上1的数量`b[i]`。 - 根据组合数学原理,任意两个数的异或结果中,该为1的情况总数为`b[i] * (n - b[i])`[^1]。 3. **总和计算**: - 将每一结果乘以对应的权重(即`2^i`),并累加得到最终答案。 #### 实现代码 以下是一个基于C++的高效实现: ```cpp #include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; vector<long long> b(32, 0); // 统计每个二进制上的1的个数 for (int i = 0; i < n; ++i) { long long a; cin >> a; for (int j = 0; j < 32; ++j) { if ((a >> j) & 1) { b[j]++; } } } long long sum = 0; for (int i = 0; i < 32; ++i) { sum += (1LL << i) * b[i] * (n - b[i]); // 计算每一的贡献 } cout << sum << endl; return 0; } ``` #### 算法解释 - **输入处理**:读取`n`个整数,并统计每个二进制上1的数量。 - **运算**:对于每个数字,逐检查是否为1,并更新对应的计数器。 - **结果计算**:根据公式`sum += (1 << i) * b[i] * (n - b[i])`计算每一的贡献[^1]。 - **输出结果**:将所有的贡献累加后输出。 #### 时间复杂度分析 - **时间复杂度**:O(n * log(max_value)),其中`log(max_value)`为最大值的二进制数。 - **间复杂度**:O(log(max_value)),用于存储每个二进制的计数。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值