Count Pairs With XOR in a Range

Count Pairs With XOR in a Range

Given a (0-indexed) integer array nums and two integers low and high , return the number of nice pairs.

A nice pair is a pair (i, j) where 0 <= i < j < nums.length and low <= (nums[i] XOR nums[j]) <= high.

Example 1:

复制代码
Input: nums = [1,4,2,7], low = 2, high = 6
Output: 6
Explanation: All nice pairs (i, j) are as follows:
    - (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
复制代码

Example 2:

复制代码
Input: nums = [9,8,4,2,1], low = 5, high = 14
Output: 8
Explanation: All nice pairs (i, j) are as follows:
​​​​​    - (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
复制代码

 Constraints:

  • 1nums.length2×104
  • 1nums[i]2×104
  • 1lowhigh2×104

 

解题思路

  一开始没想到怎么做,然后看了眼标签发现是trie就自己写出来了,很经典的trie题,主要是没想到。

  因为问的是异或后在[low, high]范围内的数,因此可以先求出异或结果不超过high的个数f(high),再求出异或结果不超过low-1的个数f(low-1),你那么[low, high]范围内的数的个数就是f(high)f(low-1)

  每个数的最大数值不超过2×104,意味着转换成二进制后最多有log2×104=15位。因为比较的时候是从最高位开始比较,因此在trie中插入某个数的二进制串时应该从最高位开始往最低位依次插入。

  当枚举到ai,此时第0i1个数都已插入到trie中,现在问前面有多少个数与ai异或后的结果不超过s,即问f(s)是多少。依次从高位往低位枚举,当枚举到第k位时,如果s的第k位为1ai的第k位为t,那么很显然如果异或后的结果x的第k位为0,那么那么x剩下的位可以任意取值都不会超过s,此时只需看看在trie中有多少数的第k位是t(因为tt=0),然后再向下走到第k位为!t的节点(因为!tt=1),对应的异或结果的第k位为1。如果s的第k位为0,那么异或后的结果x的第k位为只能取0,此时只能向下走到第k位为t的节点,对应的异或结果的第k位为0。可以发现前当枚举到第k位时,得到的异或结果的前k位与s的前k位相同(不会超过s)。

  可以发现在枚举的过程中需要知道有多少个数的第k位为某个值。这个只需要开个数组来记录每个节点会被多少个数用到,在插入的时候每走到一个节点则该节点的计数加1

  还需要注意的是在比较的过程中可能会出现下一个要走的节点不存在的情况,这时直接返回已累加的答案就好了。

  AC代码如下,时间复杂度为O(15n)

复制代码
 1 const int N = 3e5 + 10;
 2 
 3 int tr[N][2], idx;
 4 int cnt[N];
 5 
 6 class Solution {
 7 public:
 8     void add(int x) {
 9         int p = 0;
10         for (int i = 14; i >= 0; i--) {
11             int t = x >> i & 1;
12             if (!tr[p][t]) tr[p][t] = ++idx;
13             p = tr[p][t];
14             cnt[p]++;   // 每走过一个节点就加1
15         }
16     }
17     
18     int query(int x, int s) {
19         int p = 0, ret = 0;
20         for (int i = 14; i >= 0; i--) {
21             int t = x >> i & 1;
22             if (s >> i & 1) {
23                 ret += cnt[tr[p][t]];   // 把第i位为t的数的个数加上,异或后的结果的第i位为0
24                 p = tr[p][!t];  // 走到第i位为!t的节点,异或结果的第i位为1
25             }
26             else {
27                 p = tr[p][t];   // 只能保证异或后的结果的第i位为0,因此走到第i位为t的节点
28             }
29             if (p == 0) return ret; // 无法往下走
30         }
31         return ret + cnt[p];
32     }
33     
34     int countPairs(vector<int>& nums, int low, int high) {
35         int n = nums.size();
36         idx = 0;
37         memset(tr, 0, sizeof(tr));
38         memset(cnt, 0, sizeof(cnt));
39         int ret = 0;
40         for (int i = 0; i < n; i++) {
41             ret += query(nums[i], high) - query(nums[i], low - 1);
42             add(nums[i]);
43         }
44         return ret;
45     }
46 };
复制代码
posted @   onlyblues  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示