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:
解题思路
一开始没想到怎么做,然后看了眼标签发现是trie就自己写出来了,很经典的trie题,主要是没想到。
因为问的是异或后在范围内的数,因此可以先求出异或结果不超过的个数,再求出异或结果不超过的个数,你那么范围内的数的个数就是。
每个数的最大数值不超过,意味着转换成二进制后最多有位。因为比较的时候是从最高位开始比较,因此在trie中插入某个数的二进制串时应该从最高位开始往最低位依次插入。
当枚举到,此时第个数都已插入到trie中,现在问前面有多少个数与异或后的结果不超过,即问是多少。依次从高位往低位枚举,当枚举到第位时,如果的第位为,的第位为,那么很显然如果异或后的结果的第位为,那么那么剩下的位可以任意取值都不会超过,此时只需看看在trie中有多少数的第位是(因为),然后再向下走到第位为的节点(因为),对应的异或结果的第位为。如果的第位为,那么异或后的结果的第位为只能取,此时只能向下走到第位为的节点,对应的异或结果的第位为。可以发现前当枚举到第位时,得到的异或结果的前位与的前位相同(不会超过)。
可以发现在枚举的过程中需要知道有多少个数的第位为某个值。这个只需要开个数组来记录每个节点会被多少个数用到,在插入的时候每走到一个节点则该节点的计数加。
还需要注意的是在比较的过程中可能会出现下一个要走的节点不存在的情况,这时直接返回已累加的答案就好了。
AC代码如下,时间复杂度为:
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 };
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17047089.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效