leetcode:648. 单词替换

题目来源

题目描述

在这里插入图片描述

题目解析

这道题给了我们一个前缀字典,又给了一个句子,让我们将句子中较长的单次替换成其前缀(如果在前缀字典中存在的话)。

关键点:如果查找word1是不是word2的前缀

前缀哈希

需要解决的问题:

  • 切割sentence,得到每一个word:
    • 由于C++中没有split函数,所以可以采用字符串流来提取每一个单词
  • 对于每一个word,去dict中寻找最短前缀。
    • 预处理:
      • 优化:对于每一个单词,可以根据第一个字母来快速定位。比如cattle这个单词的的首字母是c,那么我们在前缀字典中找所有开头是c的前缀,为了方便查找,我们将首字母相同的前缀都放在同一个数组中,总共需要26个数组,所以我们可以定义一个二维数组来装这些前缀
      • 怎么确保最短呢?可以先按照单词的长度来给所有的前缀排序,然后再一次加入对应的数组中,这样就可以保证短的前缀在前面
    • 怎么判断是不是前缀呢?
      • 对于每一个遍历到的word,我们根据首字母来查找数组中所有以该首字母开始的前缀,然后直接用substr函数来提取单词中和前缀长度相同的子字符串来跟前缀比较,如果二者相等说明可以用前缀来替换单词,然后break掉for循环。别忘了单词之前还要加上空格
class Solution {
public:
    string replaceWords(vector<string>& dictionary, string sentence) {
        std::vector<std::vector<std::string>> vec(26);
        sort(dictionary.begin(), dictionary.end(), [](const string&a, const string& b){
            return a.size() < b.size();
        });
        for(std::string dict : dictionary){
            vec[dict[0] - 'a'].emplace_back(dict);
        }

        std::string t, ans;
        std::istringstream  ss(sentence);
        while (ss >> t){
            for(std::string &word : vec[t[0] - 'a']){
                if(t.substr(0, word.size()) == word){
                    t = word;
                    break;
                }
            }
            ans += t + " ";
        }
        ans.pop_back();
        return ans;
    }
};

在这里插入图片描述

前缀树

更好的方法是使用前缀树。

  • 先遍历dictionary,将dictionary中的单词放到前缀树中
  • 然后切割sentence,得到一个个word,然后去前缀树中查询有没有对应的前缀存在,如果有就返回这个前缀,否则原样返回

class Solution {
    struct TrieNode{
        bool isWord;
        std::vector<TrieNode*> children;

        TrieNode()
            : isWord(false)
            , children(26, nullptr)
        {
        }

        ~TrieNode(){
            for(auto it : children){
                delete it;
            }
        }
    };


    void buildTree(TrieNode* root, vector<string>& dictionary) {
        TrieNode *curr;
        for (string &word : dictionary){
            curr = root;
            for(auto ch : word){
                if(curr->children[ch - 'a'] == nullptr){
                    curr->children[ch - 'a'] = new TrieNode();
                }
                curr = curr->children[ch - 'a'];
            }
            curr->isWord = true;
        }
    }


    std::string findPrefix(TrieNode* root , const std::string &word){
        auto curr = root;
        std::string ans;
        for(auto ch : word){
            if(curr->isWord || curr->children[ch - 'a'] == nullptr){
                break;
            }
            ans += ch;
            curr = curr->children[ch - 'a'];
        }
        return curr->isWord ? ans : "";  //有前缀返回前缀,没有则返回空字符串
    }


public:
    string replaceWords(vector<string>& dictionary, string sentence) {
        TrieNode* root = new TrieNode();
        buildTree(root, dictionary);

        std::string t, ans;
        std::istringstream  ss(sentence);
        while (ss >> t){
            std::string prefix = findPrefix(root, t);
            if(prefix.empty()){
                ans += t + " ";
            }else{
                ans += prefix + " ";
            }
        }
        ans.pop_back();
        delete root;
        return ans;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值