最新华为OD机试
题目描述
给定一个连续不包含空格的字符串,该字符串仅包含英文小写字母及英文标点符号(逗号、分号、句号),同时给定词库,对该字符串进行精确分词。
说明:
-
精确分词:字符串分词后,不会出现重叠。即"ilovechina",不同词库可分割为"i,love,china",“ilove,china”,不能分割出现重叠的"i,ilove,china",i 出现重叠
-
标点符号不成词,仅用于断句
-
词库:根据外部知识库统计出来的常用词汇例:dictionary = [“i”, “love”, “china”, “lovechina”, “ilove”]
-
分词原则:采用分词顺序优先且最长匹配原则
“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
说明
标点符号为英文标点符号
解题思路
题目的要求是给定一个连续的字符串,该字符串只包含英文小写字母和英文标点符号(逗号、分号、句号),同时给出一个词库。你需要根据这个词库将字符串进行分词。
这里的分词有两个原则:
-
分词顺序优先:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择在词库中出现顺序较前的词。例如,如果词库是 [“i”, “love”, “china”, “lovechina”, “ilove”],那么字符串 “ilovechina” 应该被分割为 “ilove,china”,而不是 “i,lovechina”,因为 “ilove” 在词库中出现的顺序比 “lovechina” 要前。
-
最长匹配原则:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择长度较长的词。例如,如果词库是 [“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”。
-
首先,将字典中的每个单词插入到 Trie 中。这个过程中,Trie 会根据字典中的单词构建出相应的路径。
-
然后,开始遍历句子中的每个字符。首先遇到的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的单词 “i”,所以将 “i” 添加到结果中。
-
接下来的字符是 ‘l’,在 Trie 中可以找到以 ‘l’ 为起点的最长单词 “love”,所以将 “love” 添加到结果中。
-
然后的字符是 ‘c’,在 Trie 中可以找到以 ‘c’ 为起点的最长单词 “china”,所以将 “china” 添加到结果中。
-
接下来的字符是 ‘,’,这是一个非字母字符,直接将其添加到结果中。
-
然后的字符是 ‘t’,在 Trie 中可以找到以 ‘t’ 为起点的最长单词 “the”,所以将 “the” 添加到结果中。
-
接下来的字符是 ‘w’,在 Trie 中可以找到以 ‘w’ 为起点的最长单词 “word”,所以将 “word” 添加到结果中。
-
然后的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的最长单词 “is”,所以将 “is” 添加到结果中。
-
接下来的字符是 ‘b’,在 Trie 中可以找到以 ‘b’ 为起点的最长单词 “beauti”,所以将 “beauti” 添加到结果中。
-
最后的字符是 ‘f’,在 Trie 中可以找到以 ‘f’ 为起点的最长单词 “ful”,所以将 “ful” 添加到结果中。
-
遍历完句子中的所有字符后,得到的结果是 “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