前缀树的应用-单词替换

3 篇文章 0 订阅
2 篇文章 0 订阅

在这里插入图片描述
这道题也是一道前缀树类型的题目。先参考这题
主要在于如何去利用这个数据结构,这个结构的主要操作是,建树、查找。要处理的地方在于怎么迁移到这道题目上面来。观察题意,我们可以用pass 和end 来辅助处理。如何理解?

首先是建树,建树的过程和上一道的前缀树是一样的(当然在处理之前,要思考,是字典作为树,还是句子中的单词作为树),用句子中单词建树,数据量会很大,而且有多余的部分(分析实例,其中有很多没有词根的是直接输出的,因此我们建树的话,待会这个树会很庞大,且很多枝干是多余的存在的),反过来看,用词根建树,每个词根在树中是有存在的意义的。用句子中的单词在这颗树中查询。效率很高很多,比如首字母就查找不到,直接退出!

其次,如何用上pass end ,pass 代表词根中有经过这个字母,end代表词根中有以此字母为结束的(是遍历每个词根中的每个字母,建树的过程)

第三,将句子中的单词提取出来。

第四,在建好的词根树中,查询每个单词。pass不为0时,加入到一个新的字符串中(加入到尾部),如果end不为0 ,说明词根存在,赶紧输出前面的新字符串中。

第五,如果没有找到词根(其中包括,1.首字母就不匹配。2.词根前部分匹配,后半部分不匹配),则输出原来的单词。

typedef struct node{
    int pass;
    int end;
    //bool flag = false;       //判断是否结束
    struct node* next[26] = {nullptr};
    node(int a,int b):pass(a),end(b){}
}Node;
class Solution {
public:
    Solution() //构造函数
    {
        node_shou = new Node(0,0);
    }
    string replaceWords(vector<string>& dictionary, string sentence) {
        //建立前缀树
        build_trie(dictionary);
        //将句子切分
        vector<string> mystr;
        vector<int> biaoding;
        for(int i = 0;i<sentence.size();i++)
            if(sentence[i] == ' ')biaoding.emplace_back(i);
        biaoding.emplace_back(sentence.size());
        int chushi = 0;
        for(int j = 0;j<biaoding.size();j++)
        {
            string mid(sentence.begin()+chushi,sentence.begin()+biaoding[j]);
            mystr.emplace_back(mid);
            chushi = biaoding[j]+1;
        }
        /*for(string i:mystr)
        {
            std::cout<<i<<std::endl;
        }*/
        //依次查询句子中成分,并合成句子
        string out;
        for(int k = 0;k<mystr.size();k++)
        {
            out += query(mystr[k]);
            if(k == mystr.size()-1)break;
            out.push_back(' ');
        }
        //返回句子
        return out;
    }
    string query(string words)  //查询,有词根就返回词根,没有就返回原单词
    {
        Node* node_2 = node_shou;  //首节点
        int index = 0;
        string out;
        for(int i = 0;i<words.size();i++)
        {   index = words[i]-'a';
            if(node_2->next[index] != nullptr )
            {
                if(node_2->next[index]->pass != 0)out.push_back(words[i]);
                if(node_2->next[index]->end != 0)return out;
            }
            else
            {
                return words;
            }
            node_2 = node_2->next[index];       
        }
        return words;
    }
    void build_trie(vector<string>& dictionary)   //建树
    {
        for(int i = 0;i<dictionary.size();i++)
        {
            bulid(dictionary[i]);
        }
    }
    void bulid(string str)                       //建枝叶
    {
        Node* node_1 = node_shou;
        int index = 0;
        for(int i = 0;i<str.size();i++)
        {
            index = str[i] - 'a';
            if(node_1->next[index] == nullptr)//为空
            {
                if(i  == str.size()-1)node_1->next[index] = new Node(1,1); 
                else
                    node_1->next[index] = new Node(1,0); 
            }
            else//不为空
            {
                if(i == str.size()-1)
                {
                    node_1->next[index]->end++;
                }
                node_1->next[index]->pass++;
            }
            node_1 = node_1->next[index];
        }
    }
    
private:
    Node* node_shou;
};

代码有些冗余,如有大神指点,不胜感激呀~
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值