华为OD机考E卷200分题 - 中文分词模拟器

最新华为OD机试

题目描述

给定一个连续不包含空格的字符串,该字符串仅包含英文小写字母及英文标点符号(逗号、分号、句号),同时给定词库,对该字符串进行精确分词。

说明:

  1. 精确分词:字符串分词后,不会出现重叠。即"ilovechina",不同词库可分割为"i,love,china",“ilove,china”,不能分割出现重叠的"i,ilove,china",i 出现重叠

  2. 标点符号不成词,仅用于断句

  3. 词库:根据外部知识库统计出来的常用词汇例:dictionary = [“i”, “love”, “china”, “lovechina”, “ilove”]

  4. 分词原则:采用分词顺序优先且最长匹配原则

    “ilovechina”,假设分词结果 [i,ilove,lo,love,ch,china,lovechina],则输出 [ilove,china]

    错误输出:[i,lovechina],原因:“ilove” > 优先于 “lovechina” 成词

    错误输出:[i,love,china],原因:“ilove” > "i"遵循最长匹配原则

输入描述

第一行输入待分词语句 “ilovechina”

  • 字符串长度限制:0 < length < 256

第二行输入中文词库 “i,love,china,ch,na,ve,lo,this,is,this,word”

  • 词库长度限制:1 < length < 100000

输出描述

按顺序输出分词结果 “i,love,china”

用例1

输入

ilovechina
i,love,china,ch,na,ve,lo,this,is,the,word
12

输出

i,love,china
1

说明 无

用例2

输入

iat
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

输出

i,a,t
1

说明

单个字母,不在词库中且不成词则输出单个字母

用例3

输入

ilovechina,thewordisbeautiful
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

输出

i,love,china the,word,is,beauti,ful
1

说明

标点符号为英文标点符号

解题思路

题目的要求是给定一个连续的字符串,该字符串只包含英文小写字母和英文标点符号(逗号、分号、句号),同时给出一个词库。你需要根据这个词库将字符串进行分词。

这里的分词有两个原则:

  1. 分词顺序优先:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择在词库中出现顺序较前的词。例如,如果词库是 [“i”, “love”, “china”, “lovechina”, “ilove”],那么字符串 “ilovechina” 应该被分割为 “ilove,china”,而不是 “i,lovechina”,因为 “ilove” 在词库中出现的顺序比 “lovechina” 要前。

  2. 最长匹配原则:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择长度较长的词。例如,如果词库是 [“i”, “love”, “china”, “lovechina”, “ilove”],那么字符串 “ilovechina” 应该被分割为 “ilove,china”,而不是 “i,love,china”,因为 “ilove” 的长度比 “i” 要长。

注意,标点符号不会成为词的一部分,它们只用于断句。如果一个字符不在词库中,也不是标点符号,那么它会被当作一个单独的词。

用例模拟

ilovechina,thewordisbeautiful
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

在这个例子中,输入的句子是 “ilovechina,thewordisbeautiful”,字典中的单词是 “i”, “love”, “china”, “ch”, “na”, “ve”, “lo”, “this”, “is”, “the”, “word”, “beauti”, “tiful”, “ful”。

  1. 首先,将字典中的每个单词插入到 Trie 中。这个过程中,Trie 会根据字典中的单词构建出相应的路径。

  2. 然后,开始遍历句子中的每个字符。首先遇到的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的单词 “i”,所以将 “i” 添加到结果中。

  3. 接下来的字符是 ‘l’,在 Trie 中可以找到以 ‘l’ 为起点的最长单词 “love”,所以将 “love” 添加到结果中。

  4. 然后的字符是 ‘c’,在 Trie 中可以找到以 ‘c’ 为起点的最长单词 “china”,所以将 “china” 添加到结果中。

  5. 接下来的字符是 ‘,’,这是一个非字母字符,直接将其添加到结果中。

  6. 然后的字符是 ‘t’,在 Trie 中可以找到以 ‘t’ 为起点的最长单词 “the”,所以将 “the” 添加到结果中。

  7. 接下来的字符是 ‘w’,在 Trie 中可以找到以 ‘w’ 为起点的最长单词 “word”,所以将 “word” 添加到结果中。

  8. 然后的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的最长单词 “is”,所以将 “is” 添加到结果中。

  9. 接下来的字符是 ‘b’,在 Trie 中可以找到以 ‘b’ 为起点的最长单词 “beauti”,所以将 “beauti” 添加到结果中。

  10. 最后的字符是 ‘f’,在 Trie 中可以找到以 ‘f’ 为起点的最长单词 “ful”,所以将 “ful” 添加到结果中。

  11. 遍历完句子中的所有字符后,得到的结果是 “i,love,china,the,word,is,beauti,ful”。

所以,这个程序的输出应该是 “i,love,china,the,word,is,beauti,ful”。

C++

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm> // 添加这一行

using namespace std;

// 定义 TrieNode 类,每个节点包含一个布尔值 isWord 和一个 TrieNode 类型的数组 children
struct TrieNode {
   
   
    bool isWord;
    TrieNode* children[26];

    TrieNode() {
   
   
        isWord = false;
        for (int i = 0; i < 26; i++) {
   
   
            children[i] = nullptr;
        }
    }
};

// 创建 Trie 的根节点
TrieNode* root = new TrieNode();

// 插入方法,用于向 Trie 中插入一个单词
void insert(string word) {
   
   
    TrieNode* node = root;
    // 遍历单词中的每个字符
    for (char c : word) {
   
   
        // 如果当前字符对应的子节点为空,则创建一个新的子节点
        if (node->children[c - 'a'] == nullptr) {
   
   
            node->children[c - 'a'] = new TrieNode();
        }
        // 移动到下一个子节点
        node = node->children[c - 'a'];
    }
    // 标记当前节点为一个单词的结束
    node->isWord = true;
}

int main() {
   
   
    // 读取输入的句子,并将其转换为小写
    string sentence;
    getline(cin, sentence);
    transform(sentence.begin(), sentence.end(), sentence.begin(), ::tolower);

    // 读取输入的字典,字典中的单词以逗号分隔
    string dictionary;
    getline(cin, dictionary);
    stringstream ss(dictionary);
    string word;
    while (getline(ss, word, ',')) {
   
   
        insert(word);
    }

    vector<string> result;
    int i = 0;
    // 遍历句子中的每个字符
    while (i < sentence.size()) {
   
   
        // 如果当前字符不是字母,则直接将其添加到结果中
        if (!isalpha(sentence[i])) {
   
   
            result.push_back(sentence.substr(i, 1));
            i++;
            continue;
        }
        int j = sentence.size();
        // 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
        while (j > i) {
   
   
            TrieNode* node = root;
            bool isWord = true;
            for (int k = i; k < j; k++) {
   
   
                // 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
                if 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值