|
61 | 61 |
|
62 | 62 | 另外,对于数组异或计数问题,我们通常可以使用“0-1 字典树”来解决。
|
63 | 63 |
|
64 |
| -在字典树中,我们定义两个函数,一个是 $insert(x)$,表示将数 $x$ 插入到字典树中;另一个是 $search(x, limit)$,表示在字典树中查找与 $x$ 异或值小于 $limit$ 的数对数量。 |
| 64 | +字典树的节点定义如下: |
65 | 65 |
|
66 |
| -对于 $insert(x)$ 函数,我们将数字 $x$ 按照二进制位从高到低的顺序,插入到“0-1 字典树”中,其中字典树的每个节点表示一个二进制位,每个节点有两个子节点,表示 $0$ 和 $1$。如果当前二进制位为 $0$,则插入到左子节点,否则插入到右子节点。然后将当前节点的计数值 $cnt$ 加 $1$。 |
| 66 | +- `children[0]` 和 `children[1]` 分别表示当前节点的左右子节点; |
| 67 | +- `cnt` 表示以当前节点为结尾的数的数量。 |
67 | 68 |
|
68 |
| -对于 $search(x, limit)$ 函数,我们从字典树的根节点 `node` 开始,遍历 $x$ 的二进制位,从高到低,记当前 $x$ 的二进制位的数为 $v$。 |
| 69 | +在字典树中,我们还定义了以下两个函数: |
69 | 70 |
|
70 |
| -- 如果当前 $limit$ 的二进制位为 $1$,此时我们可以直接将答案加上与 $x$ 的当前二进制位 $v$ 相同的子节点的计数值 $cnt$,然后将当前节点移动到与 $x$ 的当前二进制位 $v$ 不同的子节点,即 `node = node.children[v ^ 1]`。继续遍历下一位。 |
71 |
| -- 如果当前 $limit$ 的二进制位为 $0$,此时我们只能将当前节点移动到与 $x$ 的当前二进制位 $v$ 相同的子节点,即 `node = node.children[v]`。继续遍历下一位。 |
| 71 | +其中一个函数是 $insert(x)$,表示将数 $x$ 插入到字典树中。该函数将数字 $x$ 按照二进制位从高到低的顺序,插入到“0-1 字典树”中。如果当前二进制位为 $0$,则插入到左子节点,否则插入到右子节点。然后将节点的计数值 $cnt$ 加 $1$。 |
72 | 72 |
|
73 |
| -遍历完 $x$ 的二进制位后,返回答案。 |
| 73 | +另一个函数是 $search(x, limit)$,表示在字典树中查找与 $x$ 异或值小于 $limit$ 的数量。该函数从字典树的根节点 `node` 开始,遍历 $x$ 的二进制位,从高到低,记当前 $x$ 的二进制位的数为 $v$。如果当前 $limit$ 的二进制位为 $1$,此时我们可以直接将答案加上与 $x$ 的当前二进制位 $v$ 相同的子节点的计数值 $cnt$,然后将当前节点移动到与 $x$ 的当前二进制位 $v$ 不同的子节点,即 `node = node.children[v ^ 1]`。继续遍历下一位。如果当前 $limit$ 的二进制位为 $0$,此时我们只能将当前节点移动到与 $x$ 的当前二进制位 $v$ 相同的子节点,即 `node = node.children[v]`。继续遍历下一位。遍历完 $x$ 的二进制位后,返回答案。 |
74 | 74 |
|
75 | 75 | 有了以上两个函数,我们就可以解决本题了。
|
76 | 76 |
|
77 |
| -我们遍历数组 `nums`,对于每个数 $x$,我们先在字典树中查找与 $x$ 异或值小于 $high+1$ 的数对数量,然后在字典树中查找与 $x$ 异或值小于 $low$ 的数对数量,将两者的差值加到答案中。然后将 $x$ 插入到字典树中。继续遍历下一个数 $x$,直到遍历完数组 `nums`。最后返回答案即可。 |
| 77 | +我们遍历数组 `nums`,对于每个数 $x$,我们先在字典树中查找与 $x$ 异或值小于 $high+1$ 的数量,然后在字典树中查找与 $x$ 异或值小于 $low$ 的数对数量,将两者的差值加到答案中。接着将 $x$ 插入到字典树中。继续遍历下一个数 $x$,直到遍历完数组 `nums`。最后返回答案即可。 |
78 | 78 |
|
79 | 79 | 时间复杂度 $O(n \times \log M)$,空间复杂度 $O(n \times \log M)$。其中 $n$ 为数组 `nums` 的长度,而 $M$ 为数组 `nums` 中的最大值。本题中我们直接取 $\log M = 16$。
|
80 | 80 |
|
@@ -103,16 +103,14 @@ class Trie:
|
103 | 103 | node = self
|
104 | 104 | ans = 0
|
105 | 105 | for i in range(15, -1, -1):
|
| 106 | + if node is None: |
| 107 | + return ans |
106 | 108 | v = x >> i & 1
|
107 | 109 | if limit >> i & 1:
|
108 | 110 | if node.children[v]:
|
109 | 111 | ans += node.children[v].cnt
|
110 |
| - if node.children[v ^ 1] is None: |
111 |
| - return ans |
112 | 112 | node = node.children[v ^ 1]
|
113 | 113 | else:
|
114 |
| - if node.children[v] is None: |
115 |
| - return ans |
116 | 114 | node = node.children[v]
|
117 | 115 | return ans
|
118 | 116 |
|
@@ -151,20 +149,14 @@ class Trie {
|
151 | 149 | public int search(int x, int limit) {
|
152 | 150 | Trie node = this;
|
153 | 151 | int ans = 0;
|
154 |
| - for (int i = 15; i >= 0; --i) { |
| 152 | + for (int i = 15; i >= 0 && node != null; --i) { |
155 | 153 | int v = (x >> i) & 1;
|
156 | 154 | if (((limit >> i) & 1) == 1) {
|
157 | 155 | if (node.children[v] != null) {
|
158 | 156 | ans += node.children[v].cnt;
|
159 | 157 | }
|
160 |
| - if (node.children[v ^ 1] == null) { |
161 |
| - return ans; |
162 |
| - } |
163 | 158 | node = node.children[v ^ 1];
|
164 | 159 | } else {
|
165 |
| - if (node.children[v] == null) { |
166 |
| - return ans; |
167 |
| - } |
168 | 160 | node = node.children[v];
|
169 | 161 | }
|
170 | 162 | }
|
@@ -207,20 +199,14 @@ public:
|
207 | 199 | int search(int x, int limit) {
|
208 | 200 | Trie* node = this;
|
209 | 201 | int ans = 0;
|
210 |
| - for (int i = 15; ~i; --i) { |
| 202 | + for (int i = 15; ~i && node; --i) { |
211 | 203 | int v = x >> i & 1;
|
212 | 204 | if (limit >> i & 1) {
|
213 | 205 | if (node->children[v]) {
|
214 | 206 | ans += node->children[v]->cnt;
|
215 | 207 | }
|
216 |
| - if (!node->children[v ^ 1]) { |
217 |
| - return ans; |
218 |
| - } |
219 | 208 | node = node->children[v ^ 1];
|
220 | 209 | } else {
|
221 |
| - if (!node->children[v]) { |
222 |
| - return ans; |
223 |
| - } |
224 | 210 | node = node->children[v];
|
225 | 211 | }
|
226 | 212 | }
|
@@ -272,20 +258,14 @@ func (this *Trie) insert(x int) {
|
272 | 258 |
|
273 | 259 | func (this *Trie) search(x, limit int) (ans int) {
|
274 | 260 | node := this
|
275 |
| - for i := 15; i >= 0; i-- { |
| 261 | + for i := 15; i >= 0 && node != nil; i-- { |
276 | 262 | v := (x >> i) & 1
|
277 | 263 | if (limit >> i & 1) == 1 {
|
278 | 264 | if node.children[v] != nil {
|
279 | 265 | ans += node.children[v].cnt
|
280 | 266 | }
|
281 |
| - if node.children[v^1] == nil { |
282 |
| - return |
283 |
| - } |
284 | 267 | node = node.children[v^1]
|
285 | 268 | } else {
|
286 |
| - if node.children[v] == nil { |
287 |
| - return |
288 |
| - } |
289 | 269 | node = node.children[v]
|
290 | 270 | }
|
291 | 271 | }
|
|
0 commit comments