|
68 | 68 |
|
69 | 69 | <!-- 这里可写通用的实现逻辑 -->
|
70 | 70 |
|
71 |
| -哈希表或前缀树实现。 |
| 71 | +**方法一:哈希表** |
| 72 | + |
| 73 | +**方法二:前缀树** |
| 74 | + |
| 75 | +题目是求两个元素的异或最大值,可以从最高位开始考虑。 |
| 76 | + |
| 77 | +我们把数组中的每个元素 $x$ 看作一个 $32$ 位的 $01$ 串,按二进制从高位到低位的顺序,插入前缀树(最低位为叶子节点)。 |
| 78 | + |
| 79 | +搜索 $x$ 时,尽量走相反的 $01$ 字符指针的策略,因为异或运算的法则是相同得 $0$,不同得 $1$,所以我们尽可能往与 $x$ 当前位相反的字符方向走,才能得到能和 $x$ 产生最大值的结果。 |
72 | 80 |
|
73 | 81 | <!-- tabs:start -->
|
74 | 82 |
|
@@ -101,53 +109,35 @@ class Solution:
|
101 | 109 | ```python
|
102 | 110 | class Trie:
|
103 | 111 | def __init__(self):
|
104 |
| - self.left = None |
105 |
| - self.right = None |
| 112 | + self.children = [None] * 2 |
| 113 | + |
| 114 | + def insert(self, x): |
| 115 | + node = self |
| 116 | + for i in range(30, -1, -1): |
| 117 | + v = (x >> i) & 1 |
| 118 | + if node.children[v] is None: |
| 119 | + node.children[v] = Trie() |
| 120 | + node = node.children[v] |
| 121 | + |
| 122 | + def search(self, x): |
| 123 | + node = self |
| 124 | + res = 0 |
| 125 | + for i in range(30, -1, -1): |
| 126 | + v = (x >> i) & 1 |
| 127 | + if node.children[v ^ 1]: |
| 128 | + res = res << 1 | 1 |
| 129 | + node = node.children[v ^ 1] |
| 130 | + else: |
| 131 | + res <<= 1 |
| 132 | + node = node.children[v] |
| 133 | + return res |
106 | 134 |
|
107 | 135 | class Solution:
|
108 | 136 | def findMaximumXOR(self, nums: List[int]) -> int:
|
109 |
| - self.root = Trie() |
110 |
| - self.highest = 30 |
111 |
| - |
112 |
| - def add(num): |
113 |
| - node = self.root |
114 |
| - for i in range(self.highest, -1, -1): |
115 |
| - bit = (num >> i) & 1 |
116 |
| - if bit == 0: |
117 |
| - if node.left is None: |
118 |
| - node.left = Trie() |
119 |
| - node = node.left |
120 |
| - else: |
121 |
| - if node.right is None: |
122 |
| - node.right = Trie() |
123 |
| - node = node.right |
124 |
| - |
125 |
| - def cal(num): |
126 |
| - node = self.root |
127 |
| - res = 0 |
128 |
| - for i in range(self.highest, -1, -1): |
129 |
| - bit = (num >> i) & 1 |
130 |
| - if bit == 0: |
131 |
| - if node.right: |
132 |
| - res = res * 2 + 1 |
133 |
| - node = node.right |
134 |
| - else: |
135 |
| - res = res * 2 |
136 |
| - node = node.left |
137 |
| - else: |
138 |
| - if node.left: |
139 |
| - res = res * 2 + 1 |
140 |
| - node = node.left |
141 |
| - else: |
142 |
| - res = res * 2 |
143 |
| - node = node.right |
144 |
| - return res |
145 |
| - |
146 |
| - res = 0 |
147 |
| - for i in range(1, len(nums)): |
148 |
| - add(nums[i - 1]) |
149 |
| - res = max(res, cal(nums[i])) |
150 |
| - return res |
| 137 | + trie = Trie() |
| 138 | + for v in nums: |
| 139 | + trie.insert(v) |
| 140 | + return max(trie.search(v) for v in nums) |
151 | 141 | ```
|
152 | 142 |
|
153 | 143 | ### **Java**
|
@@ -183,216 +173,154 @@ class Solution {
|
183 | 173 | }
|
184 | 174 | ```
|
185 | 175 |
|
186 |
| -前缀树。 |
| 176 | +前缀树: |
187 | 177 |
|
188 | 178 | ```java
|
189 |
| -class Solution { |
190 |
| - private static final int HIGHEST = 30; |
191 |
| - private Trie root; |
192 |
| - |
193 |
| - public int findMaximumXOR(int[] nums) { |
194 |
| - int res = 0; |
195 |
| - root = new Trie(); |
196 |
| - for (int i = 1; i < nums.length; ++i) { |
197 |
| - add(nums[i - 1]); |
198 |
| - res = Math.max(res, cal(nums[i])); |
| 179 | +class Trie { |
| 180 | + Trie[] children = new Trie[2]; |
| 181 | + |
| 182 | + void insert(int x) { |
| 183 | + Trie node = this; |
| 184 | + for (int i = 30; i >= 0; --i) { |
| 185 | + int v = (x >> i) & 1; |
| 186 | + if (node.children[v] == null) { |
| 187 | + node.children[v] = new Trie(); |
| 188 | + } |
| 189 | + node = node.children[v]; |
199 | 190 | }
|
200 |
| - return res; |
201 | 191 | }
|
202 | 192 |
|
203 |
| - private int cal(int num) { |
204 |
| - Trie node = root; |
| 193 | + int search(int x) { |
| 194 | + Trie node = this; |
205 | 195 | int res = 0;
|
206 |
| - for (int i = HIGHEST; i >= 0; --i) { |
207 |
| - int bit = (num >> i) & 1; |
208 |
| - if (bit == 0) { |
209 |
| - if (node.right != null) { |
210 |
| - res = res * 2 + 1; |
211 |
| - node = node.right; |
212 |
| - } else { |
213 |
| - res = res * 2; |
214 |
| - node = node.left; |
215 |
| - } |
| 196 | + for (int i = 30; i >= 0; --i) { |
| 197 | + int v = (x >> i) & 1; |
| 198 | + if (node.children[v ^ 1] != null) { |
| 199 | + res = res << 1 | 1; |
| 200 | + node = node.children[v ^ 1]; |
216 | 201 | } else {
|
217 |
| - if (node.left != null) { |
218 |
| - res = res * 2 + 1; |
219 |
| - node = node.left; |
220 |
| - } else { |
221 |
| - res = res * 2; |
222 |
| - node = node.right; |
223 |
| - } |
| 202 | + res <<= 1; |
| 203 | + node = node.children[v]; |
224 | 204 | }
|
225 | 205 | }
|
226 | 206 | return res;
|
227 | 207 | }
|
| 208 | +} |
228 | 209 |
|
229 |
| - private void add(int num) { |
230 |
| - Trie node = root; |
231 |
| - for (int i = HIGHEST; i >= 0; --i) { |
232 |
| - int bit = (num >> i) & 1; |
233 |
| - if (bit == 0) { |
234 |
| - if (node.left == null) { |
235 |
| - node.left = new Trie(); |
236 |
| - } |
237 |
| - node = node.left; |
238 |
| - } else { |
239 |
| - if (node.right == null) { |
240 |
| - node.right = new Trie(); |
241 |
| - } |
242 |
| - node = node.right; |
243 |
| - } |
| 210 | +class Solution { |
| 211 | + public int findMaximumXOR(int[] nums) { |
| 212 | + Trie trie = new Trie(); |
| 213 | + int ans = 0; |
| 214 | + for (int v : nums) { |
| 215 | + trie.insert(v); |
| 216 | + ans = Math.max(ans, trie.search(v)); |
244 | 217 | }
|
| 218 | + return ans; |
245 | 219 | }
|
246 | 220 | }
|
247 |
| - |
248 |
| -class Trie { |
249 |
| - public Trie left; |
250 |
| - public Trie right; |
251 |
| -} |
252 | 221 | ```
|
253 | 222 |
|
254 | 223 | ### **C++**
|
255 | 224 |
|
256 | 225 | ```cpp
|
257 | 226 | class Trie {
|
258 | 227 | public:
|
259 |
| - Trie* left; |
260 |
| - Trie* right; |
261 |
| -}; |
262 |
| - |
263 |
| -class Solution { |
264 |
| -public: |
265 |
| - int highest = 30; |
266 |
| - Trie* root; |
| 228 | + vector<Trie*> children; |
| 229 | + string v; |
| 230 | + Trie() : children(2) {} |
267 | 231 |
|
268 |
| - int findMaximumXOR(vector<int>& nums) { |
269 |
| - root = new Trie(); |
270 |
| - int res = 0; |
271 |
| - for (int i = 1; i < nums.size(); ++i) |
| 232 | + void insert(int x) { |
| 233 | + Trie* node = this; |
| 234 | + for (int i = 30; ~i; --i) |
272 | 235 | {
|
273 |
| - add(nums[i - 1]); |
274 |
| - res = max(res, cal(nums[i])); |
| 236 | + int v = (x >> i) & 1; |
| 237 | + if (!node->children[v]) node->children[v] = new Trie(); |
| 238 | + node = node->children[v]; |
275 | 239 | }
|
276 |
| - return res; |
277 | 240 | }
|
278 | 241 |
|
279 |
| - int cal(int num) { |
280 |
| - Trie* node = root; |
| 242 | + int search(int x) { |
| 243 | + Trie* node = this; |
281 | 244 | int res = 0;
|
282 |
| - for (int i = highest; i >= 0; --i) |
| 245 | + for (int i = 30; ~i; --i) |
283 | 246 | {
|
284 |
| - int bit = (num >> i) & 1; |
285 |
| - if (bit == 0) |
| 247 | + int v = (x >> i) & 1; |
| 248 | + if (node->children[v ^ 1]) |
286 | 249 | {
|
287 |
| - if (node->right) |
288 |
| - { |
289 |
| - res = res * 2 + 1; |
290 |
| - node = node->right; |
291 |
| - } |
292 |
| - else |
293 |
| - { |
294 |
| - res = res * 2; |
295 |
| - node = node->left; |
296 |
| - } |
| 250 | + res = res << 1 | 1; |
| 251 | + node = node->children[v ^ 1]; |
297 | 252 | }
|
298 | 253 | else
|
299 | 254 | {
|
300 |
| - if (node->left) |
301 |
| - { |
302 |
| - res = res * 2 + 1; |
303 |
| - node = node->left; |
304 |
| - } |
305 |
| - else |
306 |
| - { |
307 |
| - res = res * 2; |
308 |
| - node = node->right; |
309 |
| - } |
| 255 | + res <<= 1; |
| 256 | + node = node->children[v]; |
310 | 257 | }
|
311 | 258 | }
|
312 | 259 | return res;
|
313 | 260 | }
|
| 261 | +}; |
314 | 262 |
|
315 |
| - void add(int num) { |
316 |
| - Trie* node = root; |
317 |
| - for (int i = highest; i >= 0; --i) |
| 263 | +class Solution { |
| 264 | +public: |
| 265 | + int findMaximumXOR(vector<int>& nums) { |
| 266 | + Trie* trie = new Trie(); |
| 267 | + int ans = 0; |
| 268 | + for (int v : nums) |
318 | 269 | {
|
319 |
| - int bit = (num >> i) & 1; |
320 |
| - if (bit == 0) |
321 |
| - { |
322 |
| - if (!node->left) node->left = new Trie(); |
323 |
| - node = node->left; |
324 |
| - } |
325 |
| - else |
326 |
| - { |
327 |
| - if (!node->right) node->right = new Trie(); |
328 |
| - node = node->right; |
329 |
| - } |
| 270 | + trie->insert(v); |
| 271 | + ans = max(ans, trie->search(v)); |
330 | 272 | }
|
| 273 | + return ans; |
331 | 274 | }
|
332 | 275 | };
|
333 | 276 | ```
|
334 | 277 |
|
335 | 278 | ### **Go**
|
336 | 279 |
|
337 | 280 | ```go
|
338 |
| -const highest = 30 |
| 281 | +type Trie struct { |
| 282 | + children [26]*Trie |
| 283 | +} |
339 | 284 |
|
340 |
| -type trie struct { |
341 |
| - left, right *trie |
| 285 | +func newTrie() *Trie { |
| 286 | + return &Trie{} |
342 | 287 | }
|
343 | 288 |
|
344 |
| -func (root *trie) add(num int) { |
345 |
| - node := root |
346 |
| - for i := highest; i >= 0; i-- { |
347 |
| - bit := (num >> i) & 1 |
348 |
| - if bit == 0 { |
349 |
| - if node.left == nil { |
350 |
| - node.left = &trie{} |
351 |
| - } |
352 |
| - node = node.left |
353 |
| - } else { |
354 |
| - if node.right == nil { |
355 |
| - node.right = &trie{} |
356 |
| - } |
357 |
| - node = node.right |
| 289 | +func (this *Trie) insert(x int) { |
| 290 | + node := this |
| 291 | + for i := 30; i >= 0; i-- { |
| 292 | + v := (x >> i) & 1 |
| 293 | + if node.children[v] == nil { |
| 294 | + node.children[v] = newTrie() |
358 | 295 | }
|
| 296 | + node = node.children[v] |
359 | 297 | }
|
360 | 298 | }
|
361 | 299 |
|
362 |
| -func (root *trie) cal(num int) int { |
363 |
| - node := root |
| 300 | +func (this *Trie) search(x int) int { |
| 301 | + node := this |
364 | 302 | res := 0
|
365 |
| - for i := highest; i >= 0; i-- { |
366 |
| - bit := (num >> i) & 1 |
367 |
| - if bit == 0 { |
368 |
| - if node.right != nil { |
369 |
| - res = res*2 + 1 |
370 |
| - node = node.right |
371 |
| - } else { |
372 |
| - res = res * 2 |
373 |
| - node = node.left |
374 |
| - } |
| 303 | + for i := 30; i >= 0; i-- { |
| 304 | + v := (x >> i) & 1 |
| 305 | + if node.children[v^1] != nil { |
| 306 | + res = res<<1 | 1 |
| 307 | + node = node.children[v^1] |
375 | 308 | } else {
|
376 |
| - if node.left != nil { |
377 |
| - res = res*2 + 1 |
378 |
| - node = node.left |
379 |
| - } else { |
380 |
| - res = res * 2 |
381 |
| - node = node.right |
382 |
| - } |
| 309 | + res <<= 1 |
| 310 | + node = node.children[v] |
383 | 311 | }
|
384 | 312 | }
|
385 | 313 | return res
|
386 | 314 | }
|
387 | 315 |
|
388 | 316 | func findMaximumXOR(nums []int) int {
|
389 |
| - root := &trie{} |
390 |
| - res := 0 |
391 |
| - for i := 1; i < len(nums); i++ { |
392 |
| - root.add(nums[i-1]) |
393 |
| - res = max(res, root.cal(nums[i])) |
| 317 | + trie := newTrie() |
| 318 | + ans := 0 |
| 319 | + for _, v := range nums { |
| 320 | + trie.insert(v) |
| 321 | + ans = max(ans, trie.search(v)) |
394 | 322 | }
|
395 |
| - return res |
| 323 | + return ans |
396 | 324 | }
|
397 | 325 |
|
398 | 326 | func max(a, b int) int {
|
|
0 commit comments