diff --git a/Index/DFS.md b/Index/DFS.md index 30445347..59bd34dd 100644 --- a/Index/DFS.md +++ b/Index/DFS.md @@ -30,6 +30,7 @@ | [606. 根据二叉树创建字符串](https://leetcode-cn.com/problems/construct-string-from-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/construct-string-from-binary-tree/solution/by-ac_oier-i2sk/) | 简单 | 🤩🤩🤩🤩 | | [638. 大礼包](https://leetcode-cn.com/problems/shopping-offers/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/shopping-offers/solution/gong-shui-san-xie-yi-ti-shuang-jie-zhuan-qgk1/) | 中等 | 🤩🤩🤩🤩 | | [653. 两数之和 IV - 输入 BST](https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/solution/by-ac_oier-zr4o/) | 简单 | 🤩🤩🤩🤩 | +| [676. 实现一个魔法字典](https://leetcode.cn/problems/implement-magic-dictionary/) | [LeetCode 题解链接](https://leetcode.cn/problems/implement-magic-dictionary/solution/by-ac_oier-a01l/) | 中等 | 🤩🤩🤩🤩🤩 | | [677. 键值映射](https://leetcode-cn.com/problems/map-sum-pairs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/map-sum-pairs/solution/gong-shui-san-xie-jie-he-dfs-de-trie-yun-i4xa/) | 中等 | 🤩🤩🤩🤩 | | [690. 员工的重要性](https://leetcode-cn.com/problems/employee-importance/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/employee-importance/solution/gong-shui-san-xie-yi-ti-shuang-jie-di-gu-s79x/) | 简单 | 🤩🤩🤩 | | [691. 贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/) | [LeetCode 题解链接](https://leetcode.cn/problems/stickers-to-spell-word/solution/by-ac_oier-5vv3/) | 困难 | 🤩🤩🤩🤩 | diff --git "a/Index/\345\255\227\345\205\270\346\240\221.md" "b/Index/\345\255\227\345\205\270\346\240\221.md" index ec5819da..8cb791bd 100644 --- "a/Index/\345\255\227\345\205\270\346\240\221.md" +++ "b/Index/\345\255\227\345\205\270\346\240\221.md" @@ -5,6 +5,7 @@ | [212. 单词搜索 II](https://leetcode-cn.com/problems/word-search-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/word-search-ii/solution/gong-shui-san-xie-yi-ti-shuang-jie-hui-s-am8f/) | 困难 | 🤩🤩🤩🤩 | | [421. 数组中两个数的最大异或值](https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-bmjdg/) | 中等 | 🤩🤩🤩🤩 | | [648. 单词替换](https://leetcode.cn/problems/replace-words/) | [LeetCode 题解链接](https://leetcode.cn/problems/replace-words/solution/by-ac_oier-jecf/) | 中等 | 🤩🤩🤩🤩🤩 | +| [676. 实现一个魔法字典](https://leetcode.cn/problems/implement-magic-dictionary/) | [LeetCode 题解链接](https://leetcode.cn/problems/implement-magic-dictionary/solution/by-ac_oier-a01l/) | 中等 | 🤩🤩🤩🤩🤩 | | [677. 键值映射](https://leetcode-cn.com/problems/map-sum-pairs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/map-sum-pairs/solution/gong-shui-san-xie-jie-he-dfs-de-trie-yun-i4xa/) | 中等 | 🤩🤩🤩🤩 | | [720. 词典中最长的单词](https://leetcode-cn.com/problems/longest-word-in-dictionary/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-word-in-dictionary/solution/by-ac_oier-bmot/) | 简单 | 🤩🤩🤩🤩 | | [1707. 与数组中元素的最大异或值](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/solution/gong-shui-san-xie-jie-zhe-ge-wen-ti-lai-lypqr/) | 困难 | 🤩🤩🤩 | diff --git "a/LeetCode/641-650/648. \345\215\225\350\257\215\346\233\277\346\215\242\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/641-650/648. \345\215\225\350\257\215\346\233\277\346\215\242\357\274\210\344\270\255\347\255\211\357\274\211.md" index 3bb35847..46845469 100644 --- "a/LeetCode/641-650/648. \345\215\225\350\257\215\346\233\277\346\215\242\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/641-650/648. \345\215\225\350\257\215\346\233\277\346\215\242\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -40,8 +40,7 @@ Tag : 「字典树」 ### 基本分析 -这是一道 `Trie` 的模板题,还不了解 `Trie` 的同学可以先看前置 🧀:[【设计数据结构】实现 Trie (前缀树) -](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247488490&idx=1&sn=db2998cb0e5f08684ee1b6009b974089) +这是一道 `Trie` 的模板题,还不了解 `Trie` 的同学可以先看前置 🧀:[【设计数据结构】实现 Trie (前缀树)](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247488490&idx=1&sn=db2998cb0e5f08684ee1b6009b974089) 前置 🧀 通过图解形式讲解了 `Trie` 的结构与原理,以及提供了两种实现 `Trie` 的方式。 diff --git "a/LeetCode/671-680/676. \345\256\236\347\216\260\344\270\200\344\270\252\351\255\224\346\263\225\345\255\227\345\205\270\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/671-680/676. \345\256\236\347\216\260\344\270\200\344\270\252\351\255\224\346\263\225\345\255\227\345\205\270\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..cf817b36 --- /dev/null +++ "b/LeetCode/671-680/676. \345\256\236\347\216\260\344\270\200\344\270\252\351\255\224\346\263\225\345\255\227\345\205\270\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,109 @@ +### 题目描述 + +这是 LeetCode 上的 **[676. 实现一个魔法字典](https://leetcode.cn/problems/cut-off-trees-for-golf-event/solution/by-ac_oier-ksth/)** ,难度为 **中等**。 + +Tag : 「字典树」、「DFS」 + + + +设计一个使用单词列表进行初始化的数据结构,单词列表中的单词 互不相同 。 如果给出一个单词,请判定能否只将这个单词中一个字母换成另一个字母,使得所形成的新单词存在于你构建的字典中。 + +实现 `MagicDictionary` 类: + +* `MagicDictionary()` 初始化对象 +* `void buildDict(String[] dictionary)` 使用字符串数组 `dictionary` 设定该数据结构,`dictionary` 中的字符串互不相同 +* `bool search(String searchWord)` 给定一个字符串 `searchWord`,判定能否只将字符串中 一个 字母换成另一个字母,使得所形成的新字符串能够与字典中的任一字符串匹配。如果可以,返回 `true`;否则,返回 `false`。 + +示例: +``` +输入 +["MagicDictionary", "buildDict", "search", "search", "search", "search"] +[[], [["hello", "leetcode"]], ["hello"], ["hhllo"], ["hell"], ["leetcoded"]] + +输出 +[null, null, false, true, false, false] + +解释 +MagicDictionary magicDictionary = new MagicDictionary(); +magicDictionary.buildDict(["hello", "leetcode"]); +magicDictionary.search("hello"); // 返回 False +magicDictionary.search("hhllo"); // 将第二个 'h' 替换为 'e' 可以匹配 "hello" ,所以返回 True +magicDictionary.search("hell"); // 返回 False +magicDictionary.search("leetcoded"); // 返回 False +``` + +提示: +* $1 <= dictionary.length <= 100$ +* $1 <= dictionary[i].length <= 100$ +* `dictionary[i]` 仅由小写英文字母组成 +* `dictionary` 中的所有字符串 互不相同 +* $1 <= searchWord.length <= 100$ +* `searchWord` 仅由小写英文字母组成 +* `buildDict` 仅在 `search` 之前调用一次 +* 最多调用 $100$ 次 `search` + +--- + +### Trie + DFS + +为了方便,我们令 `dictionary` 为 `ss`,令 `searchWord` 为 `s`。 + +整体题意:给定字符串 `s`,问能否存在替换掉 `s` 中的某个字符,使得新字符串出现在 `ss` 数组中。 + +考虑如何使用「字典树/`Trie`」求解该问题: +* `buildDict` 操作:我们可以将所有的 $ss[i]$ 存入字典树中,方便后续检索; + +* `search` 操作:设计递归函数 `boolean query(String s, int idx, int p, int limit)`,其中 `s` 为待检索的字符串,`idx` 为当前处理到字符串 `s` 的哪一位,`p` 为当前搜索到字典树的索引编号(起始有 $p = 0$),`limit` 为当前剩余的替换字符次数,根据题意,`limit` 固定为 $1$,含义为必须替换掉 `s` 的一个字符。 + 对于 $s[idx]$ 而言,我们可以枚举新字符串在当前位置是何种字符($C = 26$ 个选择),若当前枚举到的字符与 $s[idx]$ 一致,则不消耗替换次数。 + 爆搜过程中替换次数为负数直接剪枝,当爆搜到结尾位置,再检查当前的字典树索引 $p$ 是否为单词结尾节点(对应查询数组 `ss` 中是否存在该字符串),以及剩余的替换次数 `limit` 是否为 $0$。 + +> **不了解「Trie / 字典树」的同学可以看前置 🧀:[字典树入门](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247488490&idx=1&sn=db2998cb0e5f08684ee1b6009b974089)。里面通过图例展示了字典树基本形态,以及提供了「数组实现」和「TrieNode 实现」两种方式,还有「数组大小估算方式」和「Trie 应用面」介绍** + +代码: +```Java +class MagicDictionary { + int N = 100 * 100, M = 26, idx = 0; + int[][] tr = new int[N][M]; + boolean[] isEnd = new boolean[N * M]; + void add(String s) { + int p = 0; + for (int i = 0; i < s.length(); i++) { + int u = s.charAt(i) - 'a'; + if (tr[p][u] == 0) tr[p][u] = ++idx; + p = tr[p][u]; + } + isEnd[p] = true; + } + boolean query(String s, int idx, int p, int limit) { + if (limit < 0) return false; + if (idx == s.length()) return isEnd[p] && limit == 0; + int u = s.charAt(idx) - 'a'; + for (int i = 0; i < 26; i++) { + if (tr[p][i] == 0) continue; + if (query(s, idx + 1, tr[p][i], i == u ? limit : limit - 1)) return true; + } + return false; + } + public void buildDict(String[] ss) { + for (String s : ss) add(s); + } + public boolean search(String s) { + return query(s, 0, 0, 1); + } +} +``` +* 时间复杂度:`buildDict` 操作需要将所有字符存入 `Trie`,复杂度为 $\sum_{i = 0}^{n - 1} len(ss[i]])$;`search` 操作在不考虑 `limit` 以及字典树中最多只有 $100$ 具体方案所带来的剪枝效果的话,最坏情况下要搜索所有 $C^L$ 个方案,其中 $C = 26$ 为字符集大小,$L = 100$ 为搜索字符串的最大长度 +* 空间复杂度:$O(N \times L \times C)$,其中 $N = 100$ 为存入 `Trie` 的最大方案数,$L = 100$ 为存入字符串的最大长度,$C = 26$ 为字符集大小 + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.676` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 +