加载笔记内容...
加载笔记内容...
Trie树(又称前缀树、字典树)是一种高效的数据结构,用于处理字符串的查询、插入和删除操作。它主要用于实现词典、搜索引擎的自动补全、拼写检查等功能。Trie树的特点是每个节点表示一个字符,从根节点到任意一个叶子节点的路径表示一个字符串。
Trie树的基本组成如下:
Trie树的主要操作包括:
Trie树的优点:
Trie树的缺点:
1class TrieNode {
2 children: Map<string,TrieNode>;
3 endOfWord: boolean;
4
5 constructor() {
6 this.children = new Map();
7 this.endOfWord = false;
8 }
9}
10
11class Trie {
12 private root;
13
14 constructor() {
15 this.root = new TrieNode();
16 }
17
18 insert(word: string): void {
19 let current = this.root;
20 for (const char of word) {
21 const children = current.children;
22 if (!children.has(char)) {
23 children.set(char, new TrieNode());
24 }
25 current = children.get(char);
26 }
27 current.endOfWord = true;
28 }
29
30 search(word: string): boolean {
31 let current = this.root;
32 for (const char of word) {
33 const children = current.children;
34 if (children.has(char)) {
35 current = children.get(char);
36 } else {
37 return false;
38 }
39 }
40 return current.endOfWord;
41 }
42
43 startsWith(prefix: string): boolean {
44 let current = this.root;
45 for (const char of prefix) {
46 const children = current.children;
47 if (children.has(char)) {
48 current = children.get(char);
49 } else {
50 return false;
51 }
52 }
53 return true;
54 }
55}
Trie Tree(字典树)是一种树形数据结构,它用于高效地存储和查找字符串。Trie Tree 的每个节点表示一个字符,而从根节点到叶子节点所经过的所有字符组成一个字符串。Trie Tree 可以在 O(长度) 的时间内实现字符串的插入、删除和查询操作。下面列举了一些 Trie Tree 的应用:
总之,Trie Tree 是一种非常实用的数据结构,可以应用于许多字符串处理场景。
1use std::collections::HashSet;
2
3pub fn find_maximum_xor(nums: Vec<i32>) -> i32 {
4 let mut max_xor = 0;
5 let mut mask = 0;
6
7 for i in (0..=31).rev() {
8 mask |= 1 << i;
9 let prefixes: HashSet<i32> = nums.iter().map(|num| num & mask).collect();
10 let temp_max_xor = max_xor | (1 << i);
11 for &prefix in &prefixes {
12 // if a ^ b = c, then a ^ c = b and b ^ c = a
13 if prefixes.contains(&(temp_max_xor ^ prefix)) {
14 max_xor = temp_max_xor;
15 break;
16 }
17 }
18 }
19
20 max_xor
21}
这是一个Rust语言的函数,名为find_maximum_xor
,其目的是从给定的整数向量(nums: Vec<i32>
)中找出两个数,使得它们的异或(XOR)值最大。
在这个函数中,异或运算的特点被充分利用:如果a ^ b = c,那么a ^ c = b并且b ^ c = a。
让我详细解释一下这段代码的逻辑:
let mut max_xor = 0; let mut mask = 0;
:创建并初始化变量max_xor
(用来记录目前找到的最大异或值)和mask
(用于生成前缀)。for i in (0..=31).rev()
:这是一个循环,从31到0,覆盖了一个32位整数的所有位。mask |= 1 << i;
:将mask的第i位设为1(i从31到0),用于在下一步中生成所有可能的i位前缀。let prefixes: HashSet<i32> = nums.iter().map(|num| num & mask).collect();
:使用mask来获取数组nums中所有数字的前i位前缀,并将这些前缀存储到HashSet中。HashSet用于高效查找。let temp_max_xor = max_xor | (1 << i);
:尝试将max_xor
的第i位设为1,看看是否有两个数能使它们的异或结果为这个值。for &prefix in &prefixes { if prefixes.contains(&(temp_max_xor ^ prefix)) {...}
:对于每个前缀,我们检查temp_max_xor ^ prefix
是否也在前缀集合中。如果存在,那么说明我们可以在数组中找到两个数,它们的前i位异或结果为temp_max_xor
。max_xor = temp_max_xor; break;
:如果我们找到这样的两个数,我们就把temp_max_xor
赋值给max_xor
,并跳出当前的for循环。max_xor
:在遍历所有的位之后,我们返回max_xor
,这就是数组中两个数能得到的最大异或结果。这个函数的主要思想是从最高位开始,试图让结果的每一位都尽可能地为1。通过使用贪心的策略,我们可以在O(n)的时间复杂度内求解这个问题,n为nums的长度。