1. 添加与搜索单词 - 数据结构设计
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary
:
WordDictionary()
初始化词典对象void addWord(word)
将word
添加到数据结构中,之后可以对它进行匹配bool search(word)
如果数据结构中存在字符串与word
匹配,则返回true
;否则,返回 false 。word
中可能包含一些'.'
,每个.
都可以表示任何一个字母。
Example 1
输入:
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
输出:
[null,null,null,null,false,true,true,true]
解释:
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // 返回 False
wordDictionary.search("bad"); // 返回 True
wordDictionary.search(".ad"); // 返回 True
wordDictionary.search("b.."); // 返回 True
Example 2
输入:
["WordDictionary","addWord","addWord","addWord","addWord","search","search","addWord","search","search","search","search","search","search"]
[[],["at"],["and"],["an"],["add"],["a"],[".at"],["bat"],[".at"],["an."],["a.d."],["b."],["a.d"],["."]]
输出:
[null,null,null,null,null,false,false,null,true,true,false,false,true,false]
代码
struct Trie {
bool isEnd;
vector<Trie *> children;
Trie() : isEnd(false), children(26, nullptr) {};
};
class WordDictionary {
private:
Trie *root;
bool searchWord(string &word, int iStart, Trie *node) {
for (int i = iStart; i < word.size(); ++i) {
if (word[i] == '.') {
return any_of(node->children.begin(), node->children.end(), [&](Trie *next) {
return next != nullptr && searchWord(word, i + 1, next);
});
} else if (!node->children[word[i] - 'a']) {
return false;
} else {
node = node->children[word[i] - 'a'];
}
}
return node->isEnd;
}
public:
WordDictionary() {
root = new Trie();
}
void addWord(string word) {
auto node = root;
for (char ch:word) {
if (!node->children[ch - 'a']) node->children[ch - 'a'] = new Trie();
node = node->children[ch - 'a'];
}
node->isEnd = true;
}
bool search(string word) {
return searchWord(word, 0, root);
}
};
2. 搜索推荐系统
给你一个产品数组 products
和一个字符串 searchWord
,products
数组中每个产品都是一个字符串。
请你设计一个推荐系统,在依次输入单词 searchWord
的每一个字母后,推荐 products
数组中前缀与 searchWord
相同的最多三个产品。如果前缀相同的可推荐产品超过三个,请按字典序返回最小的三个。
请你以二维列表的形式,返回在输入 searchWord
每个字母后相应的推荐产品的列表。
Example 1
输入:products = ["mobile","mouse","moneypot","monitor","mousepad"], searchWord = "mouse"
输出:[
["mobile","moneypot","monitor"],
["mobile","moneypot","monitor"],
["mouse","mousepad"],
["mouse","mousepad"],
["mouse","mousepad"]
]
解释:按字典序排序后的产品列表是 ["mobile","moneypot","monitor","mouse","mousepad"]
输入 m 和 mo,由于所有产品的前缀都相同,所以系统返回字典序最小的三个产品 ["mobile","moneypot","monitor"]
输入 mou, mous 和 mouse 后系统都返回 ["mouse","mousepad"]
Example 2
输入:products = ["havana"], searchWord = "havana"
输出:[["havana"],["havana"],["havana"],["havana"],["havana"],["havana"]]
代码
struct Trie {
bool isEnd;
vector<Trie *> children;
string word;
Trie() : isEnd(false), children(26, nullptr), word() {};
};
class Solution {
private:
Trie *root;
void addWord(string &s) {
auto node = root;
for (char ch:s) {
if (!node->children[ch - 'a']) node->children[ch - 'a'] = new Trie();
node = node->children[ch - 'a'];
}
node->word = s;
node->isEnd = true;
}
Trie *searchPrefix(string &s, int end) { // s[0,end)
auto node = root;
for (int i = 0; i < s.size() && i < end; i++) {
if (!node->children[s[i] - 'a']) return nullptr;
node = node->children[s[i] - 'a'];
}
return node;
}
void dfs(Trie *node, vector<string> &path) {
if (!node) return;
if (path.size() == 3) return;
if (node->isEnd) path.emplace_back(node->word);
for (int i = 0; i < 26; i++) {
if (node->children[i]) dfs(node->children[i], path);
}
}
public:
vector<vector<string>> suggestedProducts(vector<string> &products, string searchWord) {
root = new Trie();
for (auto &s:products) addWord(s);
int n = searchWord.size();
vector<vector<string>> result;
vector<string> path;
for (int i = 0; i < n; i++) {
path.clear();
auto node = searchPrefix(searchWord, i + 1);
dfs(node, path);
result.emplace_back(path);
}
return result;
}
};
3. 数组中两个数的最大异或值
给你一个整数数组 nums
,返回 nums[i] XOR nums[j]
的最大运算结果,其中 0 ≤ i ≤ j < n
。
**进阶:**你可以在 O(n)
的时间解决这个问题吗?
Example 1
输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.
Example 2
输入:nums = [0]
输出:0
代码
struct Trie {
vector<Trie *> children;
Trie() : children(2, nullptr) {}
};
class Solution {
private:
Trie *root;
void addNumber(int num) {
auto node = root;
for (int i = 30, bit; i >= 0; i--) {
bit = (num >> i) & 1;
if (!node->children[bit]) node->children[bit] = new Trie();
node = node->children[bit];
}
}
int maxXOR(int num) {
int ans = 0;
auto node = root;
for (int i = 30, bit; i >= 0; i--) {
bit = (num >> i) & 1;
if (node->children[1 - bit]) {
ans = 2 * ans + 1;
node = node->children[1 - bit];
} else {
ans *= 2;
node = node->children[bit];
}
}
return ans;
}
public:
int findMaximumXOR(vector<int> &nums) {
root = new Trie();
int ans = 0;
for (int num:nums) {
addNumber(num);
ans = max(ans, maxXOR(num));
}
return ans;
}
};
4. 与数组中元素的最大异或值
给你一个由非负整数组成的数组 nums
。另有一个查询数组 queries
,其中 queries[i] = [xi, mi]
。
第 i
个查询的答案是 xi
和任何 nums
数组中不超过 mi
的元素按位异或(XOR
)得到的最大值。换句话说,答案是 max(nums[j] XOR xi)
,其中所有 j
均满足 nums[j] <= mi
。如果 nums
中的所有元素都大于 mi
,最终答案就是 -1
。
返回一个整数数组 answer
作为查询的答案,其中 answer.length == queries.length
且 answer[i]
是第 i
个查询的答案。
Example 1
输入:nums = [0,1,2,3,4], queries = [[3,1],[1,3],[5,6]]
输出:[3,3,7]
解释:
1) 0 和 1 是仅有的两个不超过 1 的整数。0 XOR 3 = 3 而 1 XOR 3 = 2 。二者中的更大值是 3 。
2) 1 XOR 2 = 3.
3) 5 XOR 2 = 7.
Example 2
输入:nums = [5,2,4,6,6,3], queries = [[12,4],[8,1],[6,3]]
输出:[15,-1,5]
代码
struct Trie {
vector<Trie *> children;
Trie() : children(2, nullptr) {}
};
class Solution {
private:
Trie *root;
void addNumber(int num) {
auto node = root;
for (int i = 30, bit; i >= 0; i--) {
bit = (num >> i) & 1;
if (!node->children[bit]) node->children[bit] = new Trie();
node = node->children[bit];
}
}
int maxXOR(int num) {
int ans = 0;
auto node = root;
for (int i = 30, bit; i >= 0; i--) {
bit = (num >> i) & 1;
if (node->children[1 - bit]) {
ans = 2 * ans + 1;
node = node->children[1 - bit];
} else {
ans *= 2;
node = node->children[bit];
}
}
return ans;
}
public:
vector<int> maximizeXor(vector<int> &nums, vector<vector<int>> &queries) {
root = new Trie();
vector<int> idx(queries.size());
vector<int> result(queries.size(), -1);
for (int i = 0; i < idx.size(); ++i) idx[i] = i;
sort(idx.begin(), idx.end(), [&](int lo, int hi) {
return queries[lo][1] < queries[hi][1];
});
sort(nums.begin(), nums.end());
int i = 0, j = 0;
while (j < idx.size() && nums[0] > queries[idx[j]][1]) j++;
while (j < idx.size()) {
while (i < nums.size() && nums[i] <= queries[idx[j]][1]) {
addNumber(nums[i++]);
}
result[idx[j]] = maxXOR(queries[idx[j]][0]);
j++;
}
return result;
}
};