优质数对的数目

144 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

2354. 优质数对的数目

给你一个下标从0开始的正整数数组nums和一个正整数k给你一个下标从 0 开始的正整数数组 nums 和一个正整数 k 。

如果满足下述条件,则数对(num1,num2)是优质数对:如果满足下述条件,则数对 (num1, num2) 是 优质数对 :

num1num2都在数组nums中存在。num1 和 num2 都 在数组 nums 中存在。 num1ORnum2num1ANDnum2的二进制表示中值为1的位数之和大于等于knum1 OR num2 和 num1 AND num2 的二进制表示中值为 1 的位数之和大于等于 k , 其中OR是按位或操作,而AND是按位与操作。其中 OR 是按位 或 操作,而 AND 是按位 与 操作。 返回不同优质数对的数目。返回 不同 优质数对的数目。

如果 a!=c或者b!=d,则认为(a,b)(c,d)是不同的两个数对。如果 a != c 或者 b != d ,则认为 (a, b) 和 (c, d) 是不同的两个数对。 例如,(1,2)(2,1)不同。例如,(1, 2) 和 (2, 1) 不同。

注意:如果num1在数组中至少出现一次,则满足num1==num2的数对(num1,num2)也可以是优质数对。注意:如果 num1 在数组中至少出现 一次 ,则满足 num1 == num2 的数对 (num1, num2) 也可以是优质数对。

示例 1:
输入:nums = [1,2,3,1], k = 3
输出:5
解释:有如下几个优质数对:
- (3, 3):(3 AND 3) 和 (3 OR 3) 的二进制表示都等于 (11) 。值为 1 的位数和等于 2 + 2 = 4 ,大于等于 k = 3 。
- (2, 3) 和 (3, 2): (2 AND 3) 的二进制表示等于 (10) ,(2 OR 3) 的二进制表示等于 (11) 。值为 1 的位数和等于 1 + 2 = 3 。
- (1, 3) 和 (3, 1): (1 AND 3) 的二进制表示等于 (01) ,(1 OR 3) 的二进制表示等于 (11) 。值为 1 的位数和等于 1 + 2 = 3 。
所以优质数对的数目是 5
示例 2:
输入:nums = [5,1,1], k = 10
输出:0
解释:该数组中不存在优质数对。
数据范围
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= k <= 60
思路

根据题目意思,那么每一个数字的贡献只有两个
一个是自己和自己,另一个是自己和其他人
自己和自己只形成一个
自己和前面的其他人则可以形成 k2k * 2
树状数组动态修改 进行前缀和统计 这个数前面有多少个数满足要求的就是了
时间复杂度 nlog(n)nlog(n)
当然,要记得处理一下小细节,就是得不重复。所以我们需要排序去重 然后再算优质数对的个数。

class Solution {
public:
    long long countExcellentPairs(vector<int>& g, int k) {
        using ll = long long;
        ll ans{};
        sort(g.begin(), g.end());
        g.erase(unique(g.begin(), g.end()), g.end());
        vector<int> ve(66);
        int n = 65;
        auto low = [](int x) {return x & -x;};
        auto add = [&](int x) {for (int i = x; i <= n; i += low(i)) ve[i] += 1;};
        auto get = [&](int x) {
            if (x <= 0) return 0;
            int res = 0; for (int i = x; i; i -= low(i)) res += ve[i];
            return res;
        };
        auto cala = [&](int x) {
            int res = 0; while (x) {if (x&1) res ++; x >>= 1;}
            return res;
        };
        for (int i = 0; i < g.size(); i ++) {
            int siz = cala(g[i]);
            if (siz + siz >= k) ans ++;
            int val = get(n) - get(k - siz - 1);
            ans += val * 2;
            add(siz);
        }
        return ans;
    }
};