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:app
Input: s = "aaabbcc" dict = ["aaa","aab","bc"] Output: "<b>aaabbc</b>c"
Note:ui
算法:关键是找需不须要加bold这个事情怎么尽可能下降复杂度。这种问题通常输入的字符串(L)可能很长很长的,但字典大小(k)通常是有限制的,因此尽可能避免对字符串i,j限制找是否是符合条件,由于这样复杂度直接L^3了(双重循环+contains查)。而是能够换成for循环一次指着字符串开头,而后for循环全部词典来查看接下来的单词是否是以词典单词为前缀的 s.startsWith(word, i);,这样时间复杂度是O(L^2 * K)。这样在字符串输入能够无限长的状况下就降一个维度了,很能够。this
具体处理:spa
法1.用一个boolean[] isBold数组一开始这样标记好某个位置要不要加粗,后续进行加粗处理。code
法2.用Interval。一开始加入加粗区间,而后作一个mergeInterval,而后根据最后的intervals拼字符串。拼法最好是先用原来的,而后以后stringBuilder.insert(index, string); 并且注意每次加了之后后续再加标记都要再多一点offset。blog
实现1:字符串
public class Solution { 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(); } }
实现2:get
class Solution { private class Interval{ public int start; public int end; public Interval(int start, int end) { this.start = start; this.end = end; } } public String addBoldTag(String s, String[] dict) { if (s == null || s.length() == 0 || dict == null || dict.length == 0) { return s; } Set<String> set = new HashSet<>(); int maxL = Integer.MIN_VALUE; for (int i = 0; i < dict.length; i++) { set.add(dict[i]); maxL = Math.max(maxL, dict[i].length()); } List<Interval> intervals = new ArrayList<>(); for (int i = 0; i < s.length(); i++) { for (String word : dict) { if (s.startsWith(word, i)) { intervals.add(new Interval(i, i + word.length() - 1)); } } // 时间复杂度过高了 // for (int j = i; j <= s.length() && j <= i + maxL + 1; j++) { // if (set.contains(s.substring(i, j))) { // intervals.add(new Interval(i, j - 1)); // } // } } if (intervals.size() == 0) { return s; } intervals = mergeIntervals(intervals); int offset = 0; StringBuilder sb = new StringBuilder(s); for (int i = 0; i < intervals.size(); i++) { // 注意insert这种操做 sb.insert(intervals.get(i).start + offset, "<b>"); offset += 3; sb.insert(intervals.get(i).end + 1 + offset, "</b>"); offset += 4; } return sb.toString(); } private List<Interval> mergeIntervals(List<Interval> intervals) { List<Interval> result = new ArrayList<>(); Interval prev = intervals.get(0); Interval crt; for (int i = 1; i < intervals.size(); i++) { crt = intervals.get(i); if (crt.start <= prev.end + 1) { prev.end = Math.max(prev.end, crt.end); } else { result.add(prev); prev = crt; } } result.add(prev); return result; } }