题目来源
题目描述
给定一个字典 words 和一个字符串 S,将所有 S 中出现的关键词加粗(所有在标签 <b>
和 </b>
中的字母都会加粗。)
返回的字符串需要使用尽可能少的标签,当然标签应形成有效的组合。
例如,给定 words = [“ab”, “bc”] 和 S = “aabcd”,需要返回 “a<b>abc</b>d
”。注意返回 “a<b>a<b>b</b>c</b>d
” 会使用更多的标签,因此是错误的。
Example 1:
Input:
s = “abcxyz123”
dict = [“abc”,“123”]
Output:
“abcxyz123”
Example 2:
Input:
s = “aaabbcc”
dict = [“aaa”,“aab”,“bc”]
Output:
“aaabbcc”
注:
words 长度的范围为 [0, 50]。
words[i] 长度的范围为 [1, 10]。
S 长度的范围为 [0, 500]。
所有 words[i] 和 S 中的字符都为小写字母。
class Solution {
public:
string boldWords(vector<string>& words, string str){
}
};
题目解析
思路
- 使用一个数组bold,标记所有需要加粗的位置为true,初始化所有为false。
- 首先判断每个单词word是否是S的子串
- 如果是,则将子串所有的位置在bold上置true
class Solution {
public:
string boldWords(vector<string>& words, string str){
int n = str.size();
std::vector<bool> bold(n, false);
// 判断每一个word是不是str的子串
for(auto word : words){
int len = word.size();
for (int i = 0; i <= n - len; ++i) {
if(str[i] == word[0] && str.substr(i, len) == word){
for (int j = i; j < i + len; ++j) {
bold[j] = true;
}
}
}
}
// str开始添加标签
std::string res;
for (int i = 0; i < n; ++i) {
if(bold[i]){
if(i == 0 || !bold[i - 1]){
res += "<b>";
}
res.push_back(str[i]);
if(i == n || !bold[i + 1]){
res += "</b>";
}
}else{
res.push_back(str[i]);
}
}
return res;
}
};
思路
- 也可以用HashSet来代替bold数组,只是将需要加粗的位置放入hashSet中。
class Solution {
public:
string boldWords(vector<string>& words, string str){
int n = str.size();
unordered_set<int> bold;
// 判断每一个word是不是str的子串
for(auto word : words){
int len = word.size();
for (int i = 0; i <= n - len; ++i) {
if(str[i] == word[0] && str.substr(i, len) == word){
for (int j = i; j < i + len; ++j) {
bold.insert(j);
}
}
}
}
// str开始添加标签
std::string res;
for (int i = 0; i < n; ++i) {
if(bold.count(i) && !bold.count( i - 1)){
res += "<b>";
}
res.push_back(str[i]);
if (bold.count(i) && !bold.count(i + 1)){
res += "</b>";
}
}
return res;
}
};
trie + 形成区间 + 合并区间
class Solution {
class Trie{
public:
Trie *next[26] = {nullptr};
int isEnd = false;
int count = 0;
void insert(std::string &s){
Trie *curr = this;
for (char i : s) {
if(curr->next[i - 'a'] == nullptr){
curr->next[i - 'a'] = new Trie();
}
curr = curr->next[i - 'a'];
}
curr->count++;
curr->isEnd = true;
}
};
public:
string boldWords(vector<string>& words, string str){
Trie *trie = new Trie(), *curr;
for(auto &w : words){
trie->insert(w);
}
std::vector<bool> bold(str.size(), false);
int boldl = 0, boldr=-1;//开始加粗的位置l,r
for (int i = 0, j; i < str.size(); ++i) {
curr = trie;
boldl = max(boldl, i);//加黑的地方左端点
j = i;
while (j < str.size() && curr && curr->next[str[j] - 'a']){
curr = curr->next[str[j] - 'a'];
if(curr->isEnd){
boldr = j;
}
j++;
}
while(boldl <= boldr)
bold[boldl++] = true;//标记加黑
}
std::string ans;
for (int i = 0; i < str.size(); ++i) {
if((i==0 && bold[i]) || (i>0 && !bold[i-1] && bold[i]))//i起点
ans += "<b>";
ans += str[i];
if((i==str.size()-1 && bold[i]) || (i<str.size()-1 && bold[i] && !bold[i+1]))//i是终点
ans += "</b>";
}
return ans;
}
};
类似题目
类似题目 | 思路 |
---|---|
leetcode:56. 将所有重叠的区间合并到一个区间里面 Merge Intervals | 先按照起始位置排序,然后判断区间是否重叠(start[i] < end) ,如果不重叠,那么压入一个新的区间,否则更新右边界 |
leetcode: 758. 如果s中有子串在word中出现过,那么在s的那个子串的两端添加标签 bold-words-in-string | |
leetcode:616. 如果s中有子串在word中出现过,那么在s的那个子串的两端添加标签 Add Bold Tag in String | 和758题目一模一样,只是758中都是小写字母,而本题没有限制 |
591. 标签验证器Tag Validator |