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].

&nbsp;
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"]
Example 2:
Input: wordlist = ["yellow"], queries = ["YellOw"]
Output: ["yellow"]

&nbsp;
Constraints:


	1 &lt;= wordlist.length, queries.length &lt;= 5000
	1 &lt;= wordlist[i].length, queries[i].length &lt;= 7
	wordlist[i] and queries[i] consist only of only English letters.


class Solution:
    def spellchecker(self, wordlist: List[str], queries: List[str]) -> List[str]:
        n = len(wordlist)
        d = {}
        sd = {}
        vd = {}
        cd = {}
        for i in range(n):
            d[wordlist[i]] = i
            s = wordlist[i].lower()
            if s not in sd:sd[s] = i 
            m = len(wordlist[i])
            tmp = []
            emp = ""
            for j in range(m):
                if wordlist[i][j] in 'aeiouAEIOU': tmp.append(j)
                else:emp+=wordlist[i][j].lower()
            cd[i] = emp
            vd[i] = tmp
            
        ans = []
        for word in queries:
            word_lower = word.lower()
            if word in d: 
                ans.append(word)
                continue            
            elif word_lower in sd:
                ans.append(wordlist[sd[word_lower]])
                continue
            else:
                vow_word = []
                con_word = "" 
                m = len(word)
                for i in range(m):
                    if word[i] in 'aeiouAEIOU' : vow_word.append(i)
                    else: con_word += word[i].lower()
                if vow_word == []:
                    ans.append("")
                    continue
                    
                flag = False
                for i in range(n):
                    vow_tmp = vd[i]
                    con_tmp = cd[i]
                    if vow_tmp == vow_word and con_tmp == con_word:
                        ans.append(wordlist[i])
                        flag = True
                        break
                if flag == True:continue
                ans.append("")
        return ans
class Solution {
    public String[] spellchecker(String[] wordlist, String[] queries) {
        String[] ans = new String[queries.length];
        Map<String, String>[] map = new HashMap[3];
        Arrays.setAll(map, o -> new HashMap<>());
        String pattern = "[aeiou]";

        for (String w : wordlist){
            String lo = w.toLowerCase();
            map[0].put(w, "");
            map[1].putIfAbsent(lo, w);
            map[2].putIfAbsent(lo.replaceAll(pattern, "."), map[1].getOrDefault(w, w));
        }

        int i = 0;
        for (String q : queries){
            String lo = q.toLowerCase();
            String re = lo.replaceAll(pattern, ".");
            if (map[0].containsKey(q)){
                ans[i] = q;
            }else if (map[1].containsKey(lo)){
                ans[i] = map[1].get(lo);
            }else if (map[2].containsKey(re)){
                ans[i] = map[2].get(re);
            }else{
                ans[i] = "";
            }
            i++;
        }

        return ans;
    }
}
class Solution {
public:
    vector<string> spellchecker(vector<string>& wordlist, vector<string>& queries) {
        unordered_map<string, vector<int>> umap;

        // step 1: add info in umap;
        for(int curr = 0; curr < wordlist.size(); curr++){
            // case 1: add same;
            umap[wordlist[curr]].push_back({curr});
            // notice that the lowercase may appear;

            // case 2: add lowercase;
            string tmp = wordlist[curr];
            transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);

            if(umap.find(tmp) == umap.end() && tmp != wordlist[curr]) umap[tmp].push_back({curr});

            // case 3: add vowel errors;
            // convert aeiou to _;
            for(int c_index = 0; c_index < tmp.size(); c_index++){
                char c = tmp[c_index];
                if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') tmp[c_index] = '_';
            }

            if(umap.find(tmp) == umap.end()) umap[tmp].push_back({curr});
        }

        // step 2: convert queries;
        for(int curr = 0; curr < queries.size(); curr++){
            string tmp = queries[curr];
            transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);

            // case 1: check same;
            if(umap.find(queries[curr]) != umap.end()){
                queries[curr] = (umap[queries[curr]].size() == 1) ? wordlist[umap[queries[curr]][0]] : wordlist[umap[queries[curr]][1]];
                continue;
            }

            // case 2: check lowercase;
            if(umap.find(tmp) != umap.end() && tmp != queries[curr]){
                queries[curr] = wordlist[umap[tmp][0]];
                continue;
            }

            // case 3: check vowel errors;
            // convert aeiou to _;
            for(int c_index = 0; c_index < tmp.size(); c_index++){
                char c = tmp[c_index];
                if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') tmp[c_index] = '_';
            }

            if(umap.find(tmp) != umap.end()){
                queries[curr] = wordlist[umap[tmp][0]];
                continue;
            }

            // case 4: not found;
            queries[curr] = "";
        }

        return queries;
    }
};

// 1. When the query exactly matches a word in the wordlist (case-sensitive), you should return the same word back.
// 2. When the query matches a word up to capitlization, you should return the first such match in the wordlist.
// 3. When the query matches a word up to vowel errors, you should return the first such match in the wordlist.
// 4. If the query has no matches in the wordlist, you should return the empty string.
var spellchecker = function(wordlist, queries) {
  const baseList = new Set(wordlist.reverse());
  const loweredList = wordlist.reduce((map, word) => (map[normalize(word)] = word, map), {});
  const replacedList = wordlist.reduce((map, word) => (map[repVowels(word)] = word, map), {});
  return queries.map(word => (
    baseList.has(word) && word    ||
	loweredList[normalize(word)]  ||
	replacedList[repVowels(word)] ||
	''
  ));
};
var normalize = function(word) { return word.toLowerCase() };
var repVowels = function(word) { return normalize(word).replace(/[eiou]/g, 'a') };
Vowel Spellchecker