# 966. Vowel Spellchecker

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/vowel-spellchecker/

> 内容描述

```
Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word.

For a given query word, the spell checker handles two categories of spelling mistakes:

Capitalization: If the query matches a word in the wordlist (case-insensitive), then the query word is returned with the same case as the case in the wordlist.
Example: wordlist = ["yellow"], query = "YellOw": correct = "yellow"
Example: wordlist = ["Yellow"], query = "yellow": correct = "Yellow"
Example: wordlist = ["yellow"], query = "yellow": correct = "yellow"
Vowel Errors: If after replacing the vowels ('a', 'e', 'i', 'o', 'u') of the query word with any vowel individually, it matches a word in the wordlist (case-insensitive), then the query word is returned with the same case as the match in the wordlist.
Example: wordlist = ["YellOw"], query = "yollow": correct = "YellOw"
Example: wordlist = ["YellOw"], query = "yeellow": correct = "" (no match)
Example: wordlist = ["YellOw"], query = "yllw": correct = "" (no match)
In addition, the spell checker operates under the following precedence rules:

When the query exactly matches a word in the wordlist (case-sensitive), you should return the same word back.
When the query matches a word up to capitlization, you should return the first such match in the wordlist.
When the query matches a word up to vowel errors, you should return the first such match in the wordlist.
If the query has no matches in the wordlist, you should return the empty string.
Given some queries, return a list of words answer, where answer[i] is the correct word for query = queries[i].

 

Example 1:

Input: wordlist = ["KiTe","kite","hare","Hare"], queries = ["kite","Kite","KiTe","Hare","HARE","Hear","hear","keti","keet","keto"]
Output: ["kite","KiTe","KiTe","Hare","hare","","","KiTe","","KiTe"]
 

Note:

1 <= wordlist.length <= 5000
1 <= queries.length <= 5000
1 <= wordlist[i].length <= 7
1 <= queries[i].length <= 7
All strings in wordlist and queries consist only of english letters.
```

## 解题方案

> 思路 1
******- 时间复杂度: O(len(wordlist) * len(queries) * 5^len(query))******- 空间复杂度: O(len(wordlist))******

开始对于一个query的vowel变化还写了个dfs求所有的转变可能性，明摆着超时

```
class Solution:
    def spellchecker(self, wordlist, queries):
        """
        :type wordlist: List[str]
        :type queries: List[str]
        :rtype: List[str]
        """
        def dfs(q, idx):
            res = set()
            if idx >= len(q):
                return res
            if q[idx] not in 'AEIOUaeiou':
                res |= dfs(q, idx + 1)
                return res
            for c in 'aeiou':
                tmp = q[:idx] + c + q[idx + 1:]
                res.add(tmp.lower())
                res |= dfs(tmp, idx + 1)
            return res

        lookup = set(wordlist)
        lower_lookup = collections.defaultdict(list)
        for idx, word in enumerate(wordlist):
            lower_lookup[word.lower()].append(idx)
            
        def helper(w, q):
            if q in lookup:
                return q
            if q.lower() in lower_lookup:
                return wordlist[lower_lookup[q.lower()][0]]
            allwords = dfs(q, 0)
            for word in w:
                if word.lower() in allwords:
                    return word
            return ''

        res = []
        for q in queries:
            res.append(helper(wordlist, q))
        return res
```


> 思路 2
******- 时间复杂度: O(len(wordlist) * len(queries))******- 空间复杂度: O(len(wordlist))******

我发现根本不需要求出所有的vowel变化情况，比如'fifaf', 它变化的所有可能性就是25种，因为它有两个字符'i'和'a'是vowel

但是我们可以直接用'f_f_f'来替代这个字符的所有变化情况，只要对于wordlist里面的一个字符经过同样的转换之后跟'f_f_f'相等，那他们肯定是符合rule 3的

beats 100%

```python
class Solution:
    def spellchecker(self, wordlist, queries):
        """
        :type wordlist: List[str]
        :type queries: List[str]
        :rtype: List[str]
        """
        lookup = set(wordlist) # for rule 1
        
        lower_lookup = collections.defaultdict(list) # for rule 2
        for idx, word in enumerate(wordlist):
            lower_lookup[word.lower()].append(idx)
            
        def handleVowel(s):
            res = ''
            for i, c in enumerate(s):
                if c not in 'AEIOUaeiou':
                    res += c.lower()
                else:
                    res += '_'
            return res
            
        vowel_lookup = collections.defaultdict(list) # for # rule 3
        for idx, word in enumerate(wordlist):
            vowel_lookup[handleVowel(word)].append(idx)
            
        def helper(q):
            if q in lookup: # rule 1
                return q
            if q.lower() in lower_lookup: # rule 2
                return wordlist[lower_lookup[q.lower()][0]]
            if handleVowel(q) in vowel_lookup: # rule 3
                return wordlist[vowel_lookup[handleVowel(q)][0]]
            return ''

        res = []
        for query in queries:
            res.append(helper(query))
        return res
```

完全可以简化，参考牛p的[寒神](https://leetcode.com/problems/vowel-spellchecker/discuss/211189/JavaC%2B%2BPython-Two-HashMap)


```python
class Solution:
    def spellchecker(self, wordlist, queries):
        """
        :type wordlist: List[str]
        :type queries: List[str]
        :rtype: List[str]
        """
        words = {w: w for w in wordlist}
        cap = {w.lower(): w for w in wordlist[::-1]}
        vowel = {re.sub('[aeiou]', '#', w.lower()): w for w in wordlist[::-1]}
        return [words.get(w) or cap.get(w.lower()) or vowel.get(re.sub("[aeiou]", '#', w.lower()), "") for w in queries]
```






























