Related: LeetCode 758 - Bold Words in String
https://leetcode.com/articles/add-bold-tag-in-a-string/
Given a string s and a list of strings dict, you need to add a closed pair of bold tag
Approach #3 Using Boolean(Marking) Array
https://discuss.leetcode.com/topic/92112/java-solution-boolean-array
思路是建一个和字符串s等长的bold布尔型数组,表示如果该字符在单词里面就为true,那么最后我们就可以根据bold数组的真假值来添加标签了。我们遍历字符串s中的每一个字符,把遍历到的每一个字符当作起始位置,我们都匹配一遍字典中的所有单词,如果能匹配上,我们就用i + len来更新end,len是当前单词的长度,end表示字典中的单词在字符串s中结束的位置,那么如果i小于end,bold[i]就要赋值为true了。最后我们更新完bold数组了,就再遍历一遍字符串s,如果bold[i]为false,直接将s[i]加入结果res中;如果bold[i]为true,那么我们用while循环来找出所有连续为true的个数,然后在左右两端加上标签
Approach #2 Similar to Merge Interval Problem [Accepted]
We can pick up every word of the dictionary. For every word of the dictionary chosen currently, say of length , it is obvious that the substrings in only with length , can match with the . Thus, instead of blindly checking for 's match with every substring in , we check only the substrings with length . The matching substrings' indices are again added to the similar to the last approach.
Approach #1 Brute Force [Time Limit Exceeded]
https://discuss.leetcode.com/topic/92130/short-java-solution
https://blog.csdn.net/magicbean2/article/details/78991317
https://leetcode.com/articles/add-bold-tag-in-a-string/
Given a string s and a list of strings dict, you need to add a closed pair of bold tag
<b>
and </b>
to wrap the substrings in s that exist in dict. If two such substrings overlap, you need to wrap them together by only one pair of closed bold tag. Also, if two substrings wrapped by bold tags are consecutive, you need to combine them.
Example 1:
Input: s = "abcxyz123" dict = ["abc","123"] Output: "<b>abc</b>xyz<b>123</b>"
Example 2:
Input: s = "aaabbcc" dict = ["aaa","aab","bc"] Output: "<b>aaabbc</b>c"
Note:
- The given dict won't contain duplicates, and its length won't exceed 100.
- All the strings in input have length in range [1, 1000].
Approach #3 Using Boolean(Marking) Array
- Time complexity : . Three nested loops are there to fill array.
- Space complexity : . and size grows upto .
Another idea could be to merge the process of identification of the substrings in matching with the words in . To do so, we make use of an array for marking the positions of the substrings in which are present in . A True value at indicates that the current character is a part of the substring which is present in .
We identify the substrings in which are present in similar to the last approach, by considering only substrings of length for a dictionary word . Whenver such a substring is found with its beginning index as (and end index ), we mark all such positions in as True.
Thus, in this way, whenever a overlapping or consecutive matching substrings exist in , a continuous sequence of True values is present in . Keeping this idea in mind, we traverse over the string and keep on putting the current character in the resultant string . At every step, we also check if the array contains the beginning or end of a continuous sequence of True values. At the beginnning of such a sequence, we put an opening bold tag and then keep on putting the characters of till we find a position corresponding to which the last sequence of continuous True values breaks(the first False value is found). We put a closing bold tag at such a position. After this, we again keep on putting the characters of in till we find the next True value and we keep on continuing the process in the same manner.
public String addBoldTag(String s, String[] dict) { boolean[] bold = new boolean[s.length()]; for (String d: dict) { for (int i = 0; i <= s.length() - d.length(); i++) { if (s.substring(i, i + d.length()).equals(d)) { for (int j = i; j < i + d.length(); j++) bold[j] = true; } } } StringBuilder res = new StringBuilder(); for (int i = 0; i < s.length();) { if (bold[i]) { res.append("<b>"); while (i < s.length() && bold[i]) res.append(s.charAt(i++)); res.append("</b>"); } else res.append(s.charAt(i++)); } return res.toString(); }X.
https://discuss.leetcode.com/topic/92112/java-solution-boolean-array
Use a boolean array to mark if character at each position is bold or not. After that, things will become simple.
public String addBoldTag(String s, String[] dict) {
boolean[] bold = new boolean[s.length()];
for (int i = 0, end = 0; i < s.length(); i++) {
for (String word : dict) {
if (s.startsWith(word, i)) {
end = Math.max(end, i + word.length());
}
}
bold[i] = end > i;
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (!bold[i]) {
result.append(s.charAt(i));
continue;
}
int j = i;
while (j < s.length() && bold[j]) j++;
result.append("<b>" + s.substring(i, j) + "</b>");
i = j - 1;
}
return result.toString();
}
for (int i = 0, end = 0; i < s.length(); i++) { // For every character in `s`,
for (String word : dict) { // For every `word` in `dict`, we test:
// If substring s[i, i + word.length()] == word, meaning characters between i,
// i + word.length() should be `bold`.
if (s.startsWith(word, i)) {
// Use variable `end` to store known longest end of current continuous `bold` characters
end = Math.max(end, i + word.length());
}
}
// If `end` > `i`, meaning character at position `i` is within the current continuous `bold`
// characters, we mark it as `bold`.
bold[i] = end > i;
}
https://discuss.leetcode.com/topic/92130/short-java-solution public String addBoldTag(String s, String[] dict) {
int n = s.length();
int[] mark = new int[n+1];
for(String d : dict) {
int i = -1;
while((i = s.indexOf(d, i+1)) >= 0) {
mark[i]++;
mark[i + d.length()]--;
}
}
StringBuilder sb = new StringBuilder();
int sum = 0;
for(int i = 0; i <= n; i++) {
int cur = sum + mark[i];
if (cur > 0 && sum == 0) sb.append("<b>");
if (cur == 0 && sum > 0) sb.append("</b>");
if (i == n) break;
sb.append(s.charAt(i));
sum = cur;
}
return sb.toString();
}
http://www.cnblogs.com/grandyang/p/7043394.html思路是建一个和字符串s等长的bold布尔型数组,表示如果该字符在单词里面就为true,那么最后我们就可以根据bold数组的真假值来添加标签了。我们遍历字符串s中的每一个字符,把遍历到的每一个字符当作起始位置,我们都匹配一遍字典中的所有单词,如果能匹配上,我们就用i + len来更新end,len是当前单词的长度,end表示字典中的单词在字符串s中结束的位置,那么如果i小于end,bold[i]就要赋值为true了。最后我们更新完bold数组了,就再遍历一遍字符串s,如果bold[i]为false,直接将s[i]加入结果res中;如果bold[i]为true,那么我们用while循环来找出所有连续为true的个数,然后在左右两端加上标签
string addBoldTag(string s, vector<string>& dict) {
string res = "";
int n = s.size(), end = 0;
vector<bool> bold(n, false);
for (int i = 0; i < n; ++i) {
for (string word : dict) {
int len = word.size();
if (i + len <= n && s.substr(i, len) == word) {
end = max(end, i + len);
}
}
bold[i] = end > i;
}
for (int i = 0; i < n; ++i) {
if (!bold[i]) {
res.push_back(s[i]);
continue;
}
int j = i;
while (j < n && bold[j]) ++j;
res += "<b>" + s.substr(i, j - i) + "</b>";
i = j - 1;
}
return res;
}
Approach #2 Similar to Merge Interval Problem [Accepted]
We can pick up every word of the dictionary. For every word of the dictionary chosen currently, say of length , it is obvious that the substrings in only with length , can match with the . Thus, instead of blindly checking for 's match with every substring in , we check only the substrings with length . The matching substrings' indices are again added to the similar to the last approach.
- Time complexity : . Generating list will take , where is the average string length of .
- Space complexity : . size grows upto and size can grow upto in worst case.
public String addBoldTag(String s, String[] dict) { List < int[] > list = new ArrayList < > (); for (String d: dict) { for (int i = 0; i <= s.length() - d.length(); i++) { if (s.substring(i, i + d.length()).equals(d)) list.add(new int[] {i, i + d.length() - 1}); } } if (list.size() == 0) return s; Collections.sort(list, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); int start, prev = 0, end = 0; StringBuilder res = new StringBuilder(); for (int i = 0; i < list.size(); i++) { res.append(s.substring(prev, list.get(i)[0])); start = i; end = list.get(i)[1]; while (i < list.size() - 1 && list.get(i + 1)[0] <= end + 1) { end = Math.max(end, list.get(i + 1)[1]); i++; } res.append("<b>" + s.substring(list.get(start)[0], end + 1) + "</b>"); prev = end + 1; } res.append(s.substring(end + 1, s.length())); return res.toString(); }https://discuss.leetcode.com/topic/92114/java-solution-same-as-merge-interval
public String addBoldTag(String s, String[] dict) {
List<Interval> intervals = new ArrayList<>();
for (String str : dict) {
int index = -1;
index = s.indexOf(str, index);
while (index != -1) {
intervals.add(new Interval(index, index + str.length()));
index +=1;
index = s.indexOf(str, index);
}
}
System.out.println(Arrays.toString(intervals.toArray()));
intervals = merge(intervals);
System.out.println(Arrays.toString(intervals.toArray()));
int prev = 0;
StringBuilder sb = new StringBuilder();
for (Interval interval : intervals) {
sb.append(s.substring(prev, interval.start));
sb.append("<b>");
sb.append(s.substring(interval.start, interval.end));
sb.append("</b>");
prev = interval.end;
}
if (prev < s.length()) {
sb.append(s.substring(prev));
}
return sb.toString();
}
class Interval {
int start, end;
public Interval(int s, int e) {
start = s;
end = e;
}
public String toString() {
return "[" + start + ", " + end + "]" ;
}
}
public List<Interval> merge(List<Interval> intervals) {
if (intervals == null || intervals.size() <= 1) {
return intervals;
}
Collections.sort(intervals, new Comparator<Interval>(){
public int compare(Interval a, Interval b) {
return a.start - b.start;
}
});
int start = intervals.get(0).start;
int end = intervals.get(0).end;
List<Interval> res = new ArrayList<>();
for (Interval i : intervals) {
if (i.start <= end) {
end = Math.max(end, i.end);
} else {
res.add(new Interval(start, end));
start = i.start;
end = i.end;
}
}
res.add(new Interval(start, end));
return res;
}
Approach #1 Brute Force [Time Limit Exceeded]
- Time complexity : . Generating list of intervals will take , where represents string length.
- Space complexity : . size grows upto and size will be equal to the size of . Here, refers to the size of .And size can grow upto in worst case, where refers to size.
public String addBoldTag(String s, String[] dict) { List < int[] > list = new ArrayList < > (); Set < String > set = new HashSet < > (Arrays.asList(dict)); for (int i = 0; i < s.length(); i++) { for (int j = i; j < s.length(); j++) { if (set.contains(s.substring(i, j + 1))) list.add(new int[] {i, j}); } } if (list.size() == 0) return s; Collections.sort(list, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); int start, prev = 0, end = 0; StringBuilder res = new StringBuilder(); for (int i = 0; i < list.size(); i++) { res.append(s.substring(prev, list.get(i)[0])); start = i; end = list.get(i)[1]; while (i < list.size() - 1 && list.get(i + 1)[0] <= end + 1) { end = Math.max(end, list.get(i + 1)[1]); i++; } res.append("<b>" + s.substring(list.get(start)[0], end + 1) + "</b>"); prev = end + 1; } res.append(s.substring(end + 1, s.length())); return res.toString(); }
https://discuss.leetcode.com/topic/92130/short-java-solution
public String addBoldTag(String s, String[] dict) {
int n = s.length();
int[] mark = new int[n+1];
for(String d : dict) {
int i = -1;
while((i = s.indexOf(d, i+1)) >= 0) {
mark[i]++;
mark[i + d.length()]--;
}
}
StringBuilder sb = new StringBuilder();
int sum = 0;
for(int i = 0; i <= n; i++) {
int cur = sum + mark[i];
if (cur > 0 && sum == 0) sb.append("<b>");
if (cur == 0 && sum > 0) sb.append("</b>");
if (i == n) break;
sb.append(s.charAt(i));
sum = cur;
}
return sb.toString();
}
https://www.nowtoshare.com/en/Article/Index/70576https://blog.csdn.net/magicbean2/article/details/78991317
很常规的思路:找出dict中的每个单词在s中的出现区段interval,然后将这些intervals进行merge,merge之后形成的不重合的intervals就是我们需要插入<b>或者</b>的地方。
string addBoldTag(string s, vector<string>& dict) {
vector<pair<int, int>> ranges = findPairs(s, dict);
ranges = merge(ranges);
for (auto it = ranges.rbegin(); it != ranges.rend(); ++it) {
s.insert(it->second, "</b>");
s.insert(it->first, "<b>");
}
return s;
}
private:
vector<pair<int, int>> findPairs(string &s, vector<string> &dict) {
vector<pair<int, int>> res;
for (string w : dict) {
int n = w.size();
for (int i = 0; (i = s.find(w, i)) != string::npos; ++i) {
res.push_back(pair<int, int>(i, i + n));
}
}
return res;
}
vector<pair<int ,int>> merge(vector<pair<int, int>> &a) {
vector<pair<int, int>> r;
sort(a.begin(), a.end(), compare);
for (int i = 0, j = -1; i < a.size(); ++i) {
if (j < 0 || a[i].first > r[j].second) {
r.push_back(a[i]);
++j;
}
else {
r[j].second = max(r[j].second, a[i].second);
}
}
return r;
}
static bool compare(pair<int, int> &a, pair<int, int> &b) {
return a.first < b.first || a.first == b.first && a.second < b.second;
}
X. KMP
1. colored数组记录s中是否包含dict中字符串,若包含,将对应位置为'1',否则为'0' 2. 使用KMP字符串匹配算法找出s中包含的dict中字符串的所有位置,将对应colored置为'1' 3. 将colored中连续1用<b></b>包围
vector<vector<
int
>> next;
string colored =
""
;
void
getNext(vector<string>& dict) {
int
dlen = dict.size();
next.resize(dlen);
for
(
int
i = 0; i < dlen; i++) {
next[i].resize(dict[i].length());
next[i][0] = -1;
for
(
int
j = 0; j < dict[i].length() - 1; j++) {
int
k = next[i][j];
while
(k != -1 && dict[i][j] != dict[i][k]) k = next[i][k];
next[i][j+1] = k + 1;
}
}
}
void
kmp(string s, string t,
int
index) {
int
i = 0, j = 0;
while
(i < s.length()) {
if
(j == -1 || s[i] == t[j]) {
i++, j++;
if
(j == t.length()) {
while
(j != 0) colored[i - j--] =
'1'
;
i -= (t.length() - 1);
}
}
else
j = next[index][j];
}
}
public
:
string addBoldTag(string s, vector<string>& dict) {
int
slen = s.length(), dlen = dict.size();
next.resize(dlen);
getNext(dict);
for
(
int
i = 0; i < slen; i++) colored +=
"0"
;
for
(
int
i = 0; i < dlen; i++) kmp(s, dict[i], i);
string ans = (colored[0] ==
'1'
) ?
"<b>"
:
""
;
for
(
int
i = 0; i < slen; i++) {
ans += s[i];
if
(colored[i] ==
'1'
&& (colored[i + 1] ==
'0'
|| colored[i + 1] ==
'\0'
)) ans +=
"</b>"
;
else
if
(colored[i] ==
'0'
&& colored[i + 1] ==
'1'
) ans +=
"<b>"
;
}
return
ans;
}