1803. 统计异或值在范围内的数对有多少
题目描述
给你一个整数数组 nums
(下标 从 0 开始 计数)以及两个整数:low
和 high
,请返回 漂亮数对 的数目。
漂亮数对 是一个形如 (i, j)
的数对,其中 0 <= i < j < nums.length
且 low <= (nums[i] XOR nums[j]) <= high
。
示例 1
输入:nums = [1,4,2,7], low = 2, high = 6
输出:6
解释:所有漂亮数对 (i, j) 列出如下:
- (0, 1): nums[0] XOR nums[1] = 5
- (0, 2): nums[0] XOR nums[2] = 3
- (0, 3): nums[0] XOR nums[3] = 6
- (1, 2): nums[1] XOR nums[2] = 6
- (1, 3): nums[1] XOR nums[3] = 3
- (2, 3): nums[2] XOR nums[3] = 5
示例 2
输入:nums = [9,8,4,2,1], low = 5, high = 14
输出:8
解释:所有漂亮数对 (i, j) 列出如下:
- (0, 2): nums[0] XOR nums[2] = 13
- (0, 3): nums[0] XOR nums[3] = 11
- (0, 4): nums[0] XOR nums[4] = 8
- (1, 2): nums[1] XOR nums[2] = 12
- (1, 3): nums[1] XOR nums[3] = 10
- (1, 4): nums[1] XOR nums[4] = 9
- (2, 3): nums[2] XOR nums[3] = 6
- (2, 4): nums[2] XOR nums[4] = 5
提示
- 1 <= nums.length <= 2 * 104
- 1 <= nums[i] <= 2 * 104
- 1 <= low <= high <= 2 * 104
算法一:哈希表
思路
代码实现时,可以按照「统计前 k 个比特、统计前 k−1 个比特、统计前 k−2 个比特、……、统计前 1 个比特」进行,那么在遍历 cnt 的同时,可以把每个键都右移 1 位,从而得到下一次要统计的 cnt,这样不用重新遍历 nums,效率也更高。
收获
- 我一开始用暴力结果,果然超时了。这道题主要考察二进制,对我来说还是太难了…之后再回来看。
算法情况
代码
class Solution {
public:
int countPairs(vector<int>& nums, int low, int high) {
int ans = 0;
unordered_map<int, int> cnt;
for(int x : nums) ++ cnt[x];
for(++high; high; high>>=1, low>>=1){
unordered_map<int, int> nxt;
for(auto &[x, c] : cnt){
if(high % 2 && cnt.count(x ^ (high - 1))) ans += c * cnt[x ^ (high - 1)];
if(low % 2 && cnt.count(x ^ (low - 1))) ans -= c * cnt[x ^ (low - 1)];
nxt[x >> 1] += c;
}
cnt = move(nxt);
}
return ans / 2;
}
};
参考资料
-
不会字典树?只用哈希表也能做!(Python/Java/C++/Go)
-
unordered_map使用详解