1. 题目来源
2. 题目解析
需要注意一个点,当字符串完全出现了也不算做有效答案哈,必须要改变一个字符才可以。所以第一遍写的答案就没有通过…
思路:
- trie 建树
- 此时需要用 dfs 进行搜索,条件为:
- 从头搜这个字符串,搜到字符串末尾后,需要判断, trie 中是否存在这个字符串,且要求改变的次数恰好为 1 次。
- 如果上式成立,则为 true。
关键是:如何体现恰好有几个字母不同这个条件?
- 遍历 trie 时,额外维护一下当前遍历的位置已经出现了多少个不同的字符即可。
- 实际上还是遍历树,只不过在这里是 trie 树。
- 时间复杂度: O ( n ∗ m ) O(n*m) O(n∗m) 字符串总长度
- 空间复杂度: O ( n ∗ m ∗ 26 ) O(n*m*26) O(n∗m∗26)
const int N = 1e4+5;
int son[N][26], cnt[N], idx;
class MagicDictionary {
public:
void insert(string s) {
int p = 0;
for (auto &c : s) {
int u = c - 'a';
if (!son[p][u]) son[p][u] = ++ idx;
p = son[p][u];
}
cnt[p] ++ ;
}
MagicDictionary() {
memset(son, 0, sizeof son);
memset(cnt, 0, sizeof cnt);
idx = 0;
}
void buildDict(vector<string> dictionary) {
for (auto s : dictionary) insert(s);
}
bool search(string searchWord) {
// 字符串,trie 的 p 索引,u 当前位置,c 改变字符数量
auto dfs = [&](auto&& dfs, string& s, int p, int u, int c) -> bool {
if (cnt[p] > 0 && u == s.size() && c == 1) return true;
if (c > 1 || u == s.size()) return false;
for (int i = 0; i < 26; i ++ ) {
if (!son[p][i]) continue;
if (dfs(dfs, s, son[p][i], u + 1, c + (s[u] - 'a' != i)))
return true;
}
return false;
};
return dfs(dfs, searchWord, 0, 0, 0);
}
};
/**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary* obj = new MagicDictionary();
* obj->buildDict(dictionary);
* bool param_2 = obj->search(searchWord);
*/