📜  二进制数组所有对的乘积总和(1)

📅  最后修改于: 2023-12-03 15:21:40.901000             🧑  作者: Mango

二进制数组所有对的乘积总和

二进制数组是一个只包含 0 和 1 的数组。给定一个长度为 n 的二进制数组 nums,我们可以形成 n(n-1)/2 对数字。对于每个数字对 (nums[i], nums[j]),我们可以计算它们的乘积 nums[i]*nums[j]。请计算所有数字对的乘积总和。

实现
法一:暴力枚举

暴力枚举法非常简单。我们可以使用双重循环枚举所有数字对,对每对数字计算乘积并累加到结果中。时间复杂度为 $O(n^2)$,空间复杂度为 $O(1)$。

class Solution {
public:
    int binaryArrayMultiplication(vector<int>& nums) {
        int ans = 0;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = i + 1; j < nums.size(); j++) {
                ans += nums[i] * nums[j];
            }
        }
        return ans;
    }
};
法二:位运算

这是一种非常巧妙的方法,利用位运算进行优化。我们可以枚举二进制数的每一位,统计该位上 1 的个数和 0 的个数,然后将它们相乘,得到该位上贡献的乘积。最后将所有位上的乘积累加即可。时间复杂度为 $O(n\log{W})$,其中 $W$ 是数值的位数,空间复杂度为 $O(1)$。

class Solution {
public:
    int binaryArrayMultiplication(vector<int>& nums) {
        int ans = 0;
        int n = nums.size();
        for (int i = 0; i < 32; i++) {
            int cnt1 = 0, cnt0 = 0;
            for (int j = 0; j < n; j++) {
                if (nums[j] & (1 << i)) cnt1++;
                else cnt0++;
            }
            ans += cnt1 * cnt0 * (1 << i);
        }
        return ans;
    }
};
总结

本题通过暴力枚举和位运算两种方法进行解决,位运算的方法可以将时间复杂度从 $O(n^2)$ 降至 $O(n\log{W})$,是一种非常巧妙的优化手段。