字符串查找
实现一个 Trie (前缀树),包含 插入, 查询, 和 查询前缀这三个操作。
Trie trie = new Trie();
trie.insert(“apple”);
trie.search(“apple”); // 返回 true
trie.search(“app”); // 返回 false
trie.startsWith(“app”); // 返回 true
trie.insert(“app”);
trie.search(“app”); // 返回 true
思路:构造一个多叉树数据结构,每个父节点最多有26个子节点,分别表示26个字母,同时每个节点还存在一个结尾标志位,表示该节点是否位一个单词的末尾节点。树的操作是重点,首先在全局变量中,我们得到树的根节点,每次操作都从根节点出发。
插入操作就是遍历树,如果不存在相应的节点则实例化新节点,直到遍历到尾节点,并将尾节点的标志置为。
查询和查询前缀的方法类似,对树进行遍历,不存在节点直接返回false,最后返回判断尾节点的标志位。
class Node {
public Node[] val;
public boolean isEnd = false;
public Node() {
val = new Node[26];
}
}
class Trie {
Node root;
/** Initialize your data structure here. */
public Trie() {
root = new Node();
}
/** Inserts a word into the trie. */
public void insert(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i ++) {
if(cur.val[word.charAt(i) - 'a'] == null) {
cur.val[word.charAt(i) - 'a'] = new Node();
}
cur = cur.val[word.charAt(i) - 'a'];
}
cur.isEnd = true;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i++) {
if(cur.val[word.charAt(i) - 'a'] == null) return false;
cur = cur.val[word.charAt(i) - 'a'];
}
return cur.isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Node cur = root;
for(int i = 0; i < prefix.length(); i++) {
if(cur.val[prefix.charAt(i) - 'a'] == null) return false;
cur = cur.val[prefix.charAt(i) - 'a'];
}
return true;
}
}
最大异或和
给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在O(n)的时间解决这个问题吗?
leetcode
解题思路:
- 如果枚举所有情况,那么时间复杂度就是n方的了。
- 采用字典树的方法,先将所有的数字依据位放入字典树,然后再次遍历数组,查找每个数对应的最大异或值。在查找的时候,优先选择位相反的子树。
- 在构建树的时候,需要从高位到低位,这样在搜索的时候,优先选择位相反的子树,就能获取更大的值。
class Solution {
class TrieNode {
TrieNode[] son = new TrieNode[2];
}
TrieNode root = new TrieNode();
// 将x插入字段树
private void insert(int x) {
TrieNode p = root;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1;
if (p.son[u] == null) p.son[u] = new TrieNode();
p = p.son[u];
}
}
// 返回字典树中与x异或后最大的数
private int search(int x) {
TrieNode p = root;
int res = 0;
for (int i = 30; i >= 0; i--) {
int u = x >> i & 1;
if (p.son[1 ^ u] != null) { // 优先走x二进制表示中第i位取反的路径
res += 1 << i;
p = p.son[1 ^ u];
} else p = p.son[u];
}
return res;
}
public int findMaximumXOR(int[] nums) {
for (int num : nums) insert(num);
int res = 0;
for (int num : nums) res = Math.max(res, search(num));
return res;
}
}