Skip to content

Commit 45228f2

Browse files
committed
feat: add solutions to lc problem: No.1803
No.1803.Count Pairs With XOR in a Range
1 parent 2658ba6 commit 45228f2

File tree

6 files changed

+636
-5
lines changed

6 files changed

+636
-5
lines changed

solution/1800-1899/1803.Count Pairs With XOR in a Range/README.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,253 @@
5353

5454
<!-- 这里可写通用的实现逻辑 -->
5555

56+
**方法一:0-1 字典树**
57+
58+
对于这种区间 $[low, high]$ 统计的问题,我们可以考虑将其转换为统计 $[0, high]$ 和 $[0, low - 1]$ 的问题,然后相减即可得到答案。
59+
60+
在这道题中,我们可以统计有多少数对的异或值小于 $high+1$,然后再统计有多少数对的异或值小于 $low$,相减的结果就是异或值在区间 $[low, high]$ 之间的数对数量。
61+
62+
另外,对于数组异或计数问题,我们通常可以使用“0-1 字典树”来解决。
63+
64+
在字典树中,我们定义两个函数,一个是 $insert(x)$,表示将数 $x$ 插入到字典树中;另一个是 $search(x, limit)$,表示在字典树中查找与 $x$ 异或值小于 $limit$ 的数对数量。
65+
66+
对于 $insert(x)$ 函数,我们将数字 $x$ 按照二进制位从高到低的顺序,插入到“0-1 字典树”中,其中字典树的每个节点表示一个二进制位,每个节点有两个子节点,表示 $0$ 和 $1$。如果当前二进制位为 $0$,则插入到左子节点,否则插入到右子节点。然后将当前节点的计数值 $cnt$ 加 $1$。
67+
68+
对于 $search(x, limit)$ 函数,我们从字典树的根节点 `node` 开始,遍历 $x$ 的二进制位,从高到低,记当前 $x$ 的二进制位的数为 $v$。
69+
70+
- 如果当前 $limit$ 的二进制位为 $1$,此时我们可以直接将答案加上与 $x$ 的当前二进制位 $v$ 相同的子节点的计数值 $cnt$,然后将当前节点移动到与 $x$ 的当前二进制位 $v$ 不同的子节点,即 `node = node.children[v ^ 1]`。继续遍历下一位。
71+
- 如果当前 $limit$ 的二进制位为 $0$,此时我们只能将当前节点移动到与 $x$ 的当前二进制位 $v$ 相同的子节点,即 `node = node.children[v]`。继续遍历下一位。
72+
73+
遍历完 $x$ 的二进制位后,返回答案。
74+
75+
有了以上两个函数,我们就可以解决本题了。
76+
77+
我们遍历数组 `nums`,对于每个数 $x$,我们先在字典树中查找与 $x$ 异或值小于 $high+1$ 的数对数量,然后在字典树中查找与 $x$ 异或值小于 $low$ 的数对数量,将两者的差值加到答案中。然后将 $x$ 插入到字典树中。继续遍历下一个数 $x$,直到遍历完数组 `nums`。最后返回答案即可。
78+
79+
时间复杂度 $O(n \times \log M)$,空间复杂度 $O(n \times \log M)$。其中 $n$ 为数组 `nums` 的长度,而 $M$ 为数组 `nums` 中的最大值。本题中我们直接取 $\log M = 16$。
80+
5681
<!-- tabs:start -->
5782

5883
### **Python3**
5984

6085
<!-- 这里可写当前语言的特殊实现逻辑 -->
6186

6287
```python
88+
class Trie:
89+
def __init__(self):
90+
self.children = [None] * 2
91+
self.cnt = 0
6392

93+
def insert(self, x):
94+
node = self
95+
for i in range(15, -1, -1):
96+
v = x >> i & 1
97+
if node.children[v] is None:
98+
node.children[v] = Trie()
99+
node = node.children[v]
100+
node.cnt += 1
101+
102+
def search(self, x, limit):
103+
node = self
104+
ans = 0
105+
for i in range(15, -1, -1):
106+
v = x >> i & 1
107+
if limit >> i & 1:
108+
if node.children[v]:
109+
ans += node.children[v].cnt
110+
if node.children[v ^ 1] is None:
111+
return ans
112+
node = node.children[v ^ 1]
113+
else:
114+
if node.children[v] is None:
115+
return ans
116+
node = node.children[v]
117+
return ans
118+
119+
120+
class Solution:
121+
def countPairs(self, nums: List[int], low: int, high: int) -> int:
122+
ans = 0
123+
tree = Trie()
124+
for x in nums:
125+
ans += tree.search(x, high + 1) - tree.search(x, low)
126+
tree.insert(x)
127+
return ans
64128
```
65129

66130
### **Java**
67131

68132
<!-- 这里可写当前语言的特殊实现逻辑 -->
69133

70134
```java
135+
class Trie {
136+
private Trie[] children = new Trie[2];
137+
private int cnt;
138+
139+
public void insert(int x) {
140+
Trie node = this;
141+
for (int i = 15; i >= 0; --i) {
142+
int v = (x >> i) & 1;
143+
if (node.children[v] == null) {
144+
node.children[v] = new Trie();
145+
}
146+
node = node.children[v];
147+
++node.cnt;
148+
}
149+
}
150+
151+
public int search(int x, int limit) {
152+
Trie node = this;
153+
int ans = 0;
154+
for (int i = 15; i >= 0; --i) {
155+
int v = (x >> i) & 1;
156+
if (((limit >> i) & 1) == 1) {
157+
if (node.children[v] != null) {
158+
ans += node.children[v].cnt;
159+
}
160+
if (node.children[v ^ 1] == null) {
161+
return ans;
162+
}
163+
node = node.children[v ^ 1];
164+
} else {
165+
if (node.children[v] == null) {
166+
return ans;
167+
}
168+
node = node.children[v];
169+
}
170+
}
171+
return ans;
172+
}
173+
}
174+
175+
class Solution {
176+
public int countPairs(int[] nums, int low, int high) {
177+
Trie trie = new Trie();
178+
int ans = 0;
179+
for (int x : nums) {
180+
ans += trie.search(x, high + 1) - trie.search(x, low);
181+
trie.insert(x);
182+
}
183+
return ans;
184+
}
185+
}
186+
```
187+
188+
### **C++**
189+
190+
```cpp
191+
class Trie {
192+
public:
193+
Trie(): children(2), cnt(0) {}
194+
195+
void insert(int x) {
196+
Trie* node = this;
197+
for (int i = 15; ~i; --i) {
198+
int v = x >> i & 1;
199+
if (!node->children[v]) {
200+
node->children[v] = new Trie();
201+
}
202+
node = node->children[v];
203+
++node->cnt;
204+
}
205+
}
206+
207+
int search(int x, int limit) {
208+
Trie* node = this;
209+
int ans = 0;
210+
for (int i = 15; ~i; --i) {
211+
int v = x >> i & 1;
212+
if (limit >> i & 1) {
213+
if (node->children[v]) {
214+
ans += node->children[v]->cnt;
215+
}
216+
if (!node->children[v ^ 1]) {
217+
return ans;
218+
}
219+
node = node->children[v ^ 1];
220+
} else {
221+
if (!node->children[v]) {
222+
return ans;
223+
}
224+
node = node->children[v];
225+
}
226+
}
227+
return ans;
228+
}
229+
230+
private:
231+
vector<Trie*> children;
232+
int cnt;
233+
};
234+
235+
class Solution {
236+
public:
237+
int countPairs(vector<int>& nums, int low, int high) {
238+
Trie* tree = new Trie();
239+
int ans = 0;
240+
for (int& x : nums) {
241+
ans += tree->search(x, high + 1) - tree->search(x, low);
242+
tree->insert(x);
243+
}
244+
return ans;
245+
}
246+
};
247+
```
248+
249+
### **Go**
250+
251+
```go
252+
type Trie struct {
253+
children [2]*Trie
254+
cnt int
255+
}
256+
257+
func newTrie() *Trie {
258+
return &Trie{}
259+
}
260+
261+
func (this *Trie) insert(x int) {
262+
node := this
263+
for i := 15; i >= 0; i-- {
264+
v := (x >> i) & 1
265+
if node.children[v] == nil {
266+
node.children[v] = newTrie()
267+
}
268+
node = node.children[v]
269+
node.cnt++
270+
}
271+
}
272+
273+
func (this *Trie) search(x, limit int) (ans int) {
274+
node := this
275+
for i := 15; i >= 0; i-- {
276+
v := (x >> i) & 1
277+
if (limit >> i & 1) == 1 {
278+
if node.children[v] != nil {
279+
ans += node.children[v].cnt
280+
}
281+
if node.children[v^1] == nil {
282+
return
283+
}
284+
node = node.children[v^1]
285+
} else {
286+
if node.children[v] == nil {
287+
return
288+
}
289+
node = node.children[v]
290+
}
291+
}
292+
return
293+
}
71294
295+
func countPairs(nums []int, low int, high int) (ans int) {
296+
tree := newTrie()
297+
for _, x := range nums {
298+
ans += tree.search(x, high+1) - tree.search(x, low)
299+
tree.insert(x)
300+
}
301+
return
302+
}
72303
```
73304

74305
### **...**

0 commit comments

Comments
 (0)