LC 966. Vowel Spellchecker

Posted ethanhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LC 966. Vowel Spellchecker相关的知识,希望对你有一定的参考价值。

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

 

踩坑踩了一个下午,掉到坑里出不来了。

Runtime: 96 ms, faster than 100.00% of C++ online submissions for Vowel Spellchecker.

第一种是我的做法 修改了TrieNode的结构,让它带了一个case_sensitive的标志位。如果带上大小写搜索,

每次需要判断字符的大小写,这样得到的是第一种准确的搜索。如果不敏感,就全部放在小写的这个节点里。

为了满足题意,大小写不敏感的可能有多种,那么Trie节点带一个数组比较合适。

注意:

1. 本来的字典可能有重复,我去。。。

2. 需要返回最小的index,那就把所有的求出来以后再求最小的index。

写了一个下午。

class TrieNode{
public:
  string word;
  vector<string> wordlist;
  TrieNode* lowercase[26];
  TrieNode* uppercase[26];
  TrieNode(){
    for(int i=0; i<26; i++) lowercase[i] = nullptr;
    for(int i=0; i<26; i++) uppercase[i] = nullptr;
  }
};

class Trie{
public:
  TrieNode* root;
  Trie(const vector<string>& wordlist, bool case_sensitive = true){
    root = new TrieNode();
    BuildTrie(wordlist, case_sensitive);
  }
  void BuildTrie(const vector<string>& wordlist, bool case_sensitive = true){

    for(int i=0; i<wordlist.size(); i++){
      TrieNode* tmp = root;
      for(int j=0; j<wordlist[i].size(); j++){
        char tmpchar = wordlist[i][j];
        int idx = 0;
        if(!case_sensitive){
          if(tmpchar >= A && tmpchar <= Z){
            idx = tmpchar - A;
          }else idx = tmpchar - a;
          if(!tmp->lowercase[idx]) tmp->lowercase[idx] = new TrieNode();
          tmp = tmp->lowercase[idx];
        }else{
          if(tmpchar >= A && tmpchar <= Z){
            idx = tmpchar - A;
            if(!tmp->uppercase[idx]) tmp->uppercase[idx] = new TrieNode();
            tmp = tmp->uppercase[idx];
          }else {
            idx = tmpchar - a;
            if(!tmp->lowercase[idx]) tmp->lowercase[idx] = new TrieNode();
            tmp = tmp->lowercase[idx];
          }
        }
      }
      if(case_sensitive){
        tmp->word = wordlist[i];
      }else {
        tmp->wordlist.push_back(wordlist[i]);
      }
    }
  }
  bool hasword(string word, string& foundword, bool case_sensitive = true){
    TrieNode* tmp = root;
    locale loc;
    for(int i=0; i<word.size(); i++){
      char tmpchar = word[i];
      int idx = 0;
      if(!case_sensitive){
        tmpchar = tolower(tmpchar, loc);
        idx = tmpchar - a;
        if(!tmp->lowercase[idx]) return false;
        tmp = tmp->lowercase[idx];
      }else {
        if(tmpchar >= A && tmpchar <= Z) {
          idx = tmpchar - A;
          if(!tmp->uppercase[idx]) return false;
          tmp = tmp->uppercase[idx];
        } else {
          idx = tmpchar - a;
          if(!tmp->lowercase[idx]) return false;
          tmp = tmp->lowercase[idx];
        }
      }
    }
    if(!case_sensitive) {
      if(!tmp->wordlist.empty()){
        foundword = tmp->wordlist[0];
        return true;
      }
      return false;
    }
    if(!tmp->word.empty()) {
      foundword = tmp->word;
      return true;
    }
    return false;
  }
};

class Solution {
public:
  set<char> vset;
  unordered_map<string,int> mp;
  vector<string> spellchecker(vector<string>& wordlist, vector<string>& queries) {
    for(int i=0; i<wordlist.size(); i++){
      mp[wordlist[i]] = i;
    }
    vset.insert(a);vset.insert(e);vset.insert(i);
    vset.insert(o);vset.insert(u);
    vector<string> ret;
    Trie trie_case_sensi = Trie(wordlist);
    Trie trie_not_case_sensi = Trie(wordlist, false);
    for(int i=0; i<queries.size(); i++){
      string foundword;
      vector<string> foundwordvec;
      if(trie_case_sensi.hasword(queries[i],foundword)) {
        ret.push_back(queries[i]);
      }else if(trie_not_case_sensi.hasword(queries[i], foundword, false)){
        ret.push_back(foundword);
      }else {
        dfs(trie_not_case_sensi.root, queries[i], foundwordvec, 0);
        int minidx = wordlist.size();
        for(auto x : foundwordvec) minidx = min(minidx, mp[x]);
        if(minidx == wordlist.size()) ret.push_back("");
        else ret.push_back(wordlist[minidx]);
      }
    }
    return ret;
  }

  void dfs(const TrieNode* root,string query, vector<string>& ret, int start){
    if(start == query.size()){
      assert(!root->wordlist.empty());
      ret.push_back(root->wordlist[0]);
      return ;
    }
    std::locale loc;
    char c = tolower(query[start],loc);
    int idx = 0;
    idx = c - a;
    if(vset.count(c)){
      for(auto it = vset.begin(); it != vset.end(); it++){
        char vsub = *it;
        int newidx = 0;
        newidx = vsub - a;
        if(!root->lowercase[newidx]) continue;
        TrieNode* nextroot = root->lowercase[newidx];
        dfs(nextroot, query, ret, start+1);
      }
    }else{
      if(!root->lowercase[idx]) return ;
      TrieNode* nextroot = root->lowercase[idx];
      dfs(nextroot, query, ret, start+1);
    }
  }
};

 

 

下面看看网上的大神的解法,很简单,既然aeiou都能互相匹配,那就把aeiou变成#,这样一来不就行了么!真是厉害。

class Solution {
    public String[] spellchecker(String[] wordlist, String[] queries) {
        Set<String> words = new HashSet<>(Arrays.asList(wordlist));
        HashMap<String, String> cap = new HashMap<>();
        HashMap<String, String> vowel = new HashMap<>();
        for (String w : wordlist) {
            String lower = w.toLowerCase(), devowel = lower.replaceAll("[aeiou]", "#");
            cap.putIfAbsent(lower, w);
            vowel.putIfAbsent(devowel, w);
        }
        for (int i = 0; i < queries.length; ++i) {
            if (words.contains(queries[i])) continue;
            String lower = queries[i].toLowerCase(), devowel = lower.replaceAll("[aeiou]", "#");
            if (cap.containsKey(lower)) {
                queries[i] = cap.get(lower);
            } else if (vowel.containsKey(devowel)) {
                queries[i] = vowel.get(devowel);
            } else {
                queries[i] = "";
            }
        }
        return queries;
    }
}

 

以上是关于LC 966. Vowel Spellchecker的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode-966 Vowel Spellchecker(元音拼写检查器)

345.Reverse Vowel of a String

c_cpp Longest_common_vowel_subsequence

HDU 3079 Vowel Counting (水题。。。判断元音)

[LeetCode] 2559. Count Vowel Strings in Ranges

神仙题