Talentd
FleetCode
Make and follow sheets.Sign in

Add Bold Tag in String solution and explanation

MediumArrayHash TableStringString Matching4 min read51.4% acceptanceUpdated 23 Mar 2026Premium elsewhere, free here
LeetCode 616. Add Bold Tag in StringHappy Coding · 14:51 · 4K viewsWatch on YouTube
6 more videos on this problem
  1. LeetCode 616. Add Bold Tag in StringHappy Coding · 14:51 · 4K views
  2. ADD BOLD TAG IN STRING | LEETCODE 616 | PYTHON SOLUTIONCracking FAANG · 13:19 · 3K views
  3. Facebook Coding Interview Question | Leetcode 616 | Add Bold Tag in StringWorkWithGoogler · 21:48 · 2K views
  4. LeetCode 616. Add Bold Tag in String | JSer - JavaScript & AlgorithmJSer · 20:30 · 1K views
  5. 616 Add Bold Tag in StringJeremy Huang · 14:30 · 239 views
  6. 616. Add Bold Tag in StringJust Coding, with Jie · 17:22 · 88 views
  7. LeetCode 616: Add Bold Tag in StringAlitaCode · 28:17 · 3 views

The problem

You are given a string s and an array of strings words.

You should add a closed pair of bold tag <b> and </b> to wrap the substrings in s that exist in words.

  • If two such substrings overlap, you should wrap them together with only one pair of closed bold-tag.
  • If two substrings wrapped by bold tags are consecutive, you should combine them.

Return s after adding the bold tags.

Example 1:

Input: s = "abcxyz123", words = ["abc","123"]
Output: "<b>abc</b>xyz<b>123</b>"
Explanation: The two strings of words are substrings of s as following: "abcxyz123".
We add <b> before each substring and </b> after each substring.

Example 2:

Input: s = "aaabbb", words = ["aa","b"]
Output: "<b>aaabbb</b>"
Explanation: 
"aa" appears as a substring two times: "aaabbb" and "aaabbb".
"b" appears as a substring three times: "aaabbb", "aaabbb", and "aaabbb".
We add <b> before each substring and </b> after each substring: "<b>a<b>a</b>a</b><b>b</b><b>b</b><b>b</b>".
Since the first two <b>'s overlap, we merge them: "<b>aaa</b><b>b</b><b>b</b><b>b</b>".
Since now the four <b>'s are consecutive, we merge them: "<b>aaabbb</b>".

Constraints:

  • 1 <= s.length <= 1000
  • 0 <= words.length <= 100
  • 1 <= words[i].length <= 1000
  • s and words[i] consist of English letters and digits.
  • All the values of words are unique.

Note: This question is the same as 758. Bold Words in String.

Approach overview

Problem Overview: Given a string s and a list of dictionary words, wrap every substring in s that appears in the dictionary with <b> and </b>. Overlapping or adjacent matches must be merged into a single bold region.

Approach 1: Brute Force Matching + Interval Merge (O(n * k * L) time, O(n) space)

Scan the string from every index and check whether any dictionary word matches starting at that position using substring comparison. For each match, mark the covered indices in a boolean array or store intervals like [start, end]. After processing all matches, merge overlapping or adjacent intervals and construct the final string by inserting <b> and </b> around bold segments. This approach is straightforward and easy to implement, but repeated substring comparisons make it slower when the dictionary is large.

Approach 2: Boolean Marking with Longest Match Tracking (O(n * k * L) time, O(n) space)

Instead of storing intervals, maintain a boolean array bold[i] indicating whether character i should be bold. While iterating through s, check every dictionary word with a prefix comparison like s.startswith(word, i). Track the farthest index that should remain bold and mark characters up to that boundary. Finally, build the output string while opening a <b> tag when entering a bold region and closing it when leaving one. This method avoids explicit interval merging and is often the cleanest implementation.

Approach 3: Trie-Based String Matching (O(n * L) time, O(W * L) space)

Build a Trie from the dictionary words. Starting at each index in s, traverse the Trie while characters continue to match. Whenever a word end is reached, update the farthest bold boundary. This reduces redundant comparisons because common prefixes are shared in the Trie. The technique is common in string matching problems and works well when the dictionary contains many overlapping prefixes. Use an array or interval list to mark bold positions and generate the final string.

Recommended for interviews: The boolean marking approach is usually expected. It demonstrates clear reasoning about substring matching and interval merging while keeping the implementation simple. Mentioning a Trie optimization shows deeper understanding of scalable string matching techniques.

Solution

class Trie:
    def __init__(self):
        self.children = [None] * 128
        self.is_end = False

    def insert(self, word):
        node = self
        for c in word:
            idx = ord(c)
            if node.children[idx] is None:
                node.children[idx] = Trie()
            node = node.children[idx]
        node.is_end = True


class Solution:
    def addBoldTag(self, s: str, words: List[str]) -> str:
        trie = Trie()
        for w in words:
            trie.insert(w)
        n = len(s)
        pairs = []
        for i in range(n):
            node = trie
            for j in range(i, n):
                idx = ord(s[j])
                if node.children[idx] is None:
                    break
                node = node.children[idx]
                if node.is_end:
                    pairs.append([i, j])
        if not pairs:
            return s
        st, ed = pairs[0]
        t = []
        for a, b in pairs[1:]:
            if ed + 1 < a:
                t.append([st, ed])
                st, ed = a, b
            else:
                ed = max(ed, b)
        t.append([st, ed])

        ans = []
        i = j = 0
        while i < n:
            if j == len(t):
                ans.append(s[i:])
                break
            st, ed = t[j]
            if i < st:
                ans.append(s[i:st])
            ans.append('<b>')
            ans.append(s[st : ed + 1])
            ans.append('</b>')
            j += 1
            i = ed + 1

        return ''.join(ans)
class Trie {
    Trie[] children = new Trie[128];
    boolean isEnd;

    public void insert(String word) {
        Trie node = this;
        for (char c : word.toCharArray()) {
            if (node.children[c] == null) {
                node.children[c] = new Trie();
            }
            node = node.children[c];
        }
        node.isEnd = true;
    }
}

class Solution {
    public String addBoldTag(String s, String[] words) {
        Trie trie = new Trie();
        for (String w : words) {
            trie.insert(w);
        }
        List<int[]> pairs = new ArrayList<>();
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            Trie node = trie;
            for (int j = i; j < n; ++j) {
                int idx = s.charAt(j);
                if (node.children[idx] == null) {
                    break;
                }
                node = node.children[idx];
                if (node.isEnd) {
                    pairs.add(new int[] {i, j});
                }
            }
        }
        if (pairs.isEmpty()) {
            return s;
        }
        List<int[]> t = new ArrayList<>();
        int st = pairs.get(0)[0], ed = pairs.get(0)[1];
        for (int j = 1; j < pairs.size(); ++j) {
            int a = pairs.get(j)[0], b = pairs.get(j)[1];
            if (ed + 1 < a) {
                t.add(new int[] {st, ed});
                st = a;
                ed = b;
            } else {
                ed = Math.max(ed, b);
            }
        }
        t.add(new int[] {st, ed});
        int i = 0, j = 0;
        StringBuilder ans = new StringBuilder();
        while (i < n) {
            if (j == t.size()) {
                ans.append(s.substring(i));
                break;
            }
            st = t.get(j)[0];
            ed = t.get(j)[1];
            if (i < st) {
                ans.append(s.substring(i, st));
            }
            ++j;
            ans.append("<b>");
            ans.append(s.substring(st, ed + 1));
            ans.append("</b>");
            i = ed + 1;
        }
        return ans.toString();
    }
}
class Trie {
public:
    vector<Trie*> children;
    bool isEnd;

    Trie() {
        children.resize(128);
        isEnd = false;
    }

    void insert(string word) {
        Trie* node = this;
        for (char c : word) {
            if (!node->children[c]) node->children[c] = new Trie();
            node = node->children[c];
        }
        node->isEnd = true;
    }
};

class Solution {
public:
    string addBoldTag(string s, vector<string>& words) {
        Trie* trie = new Trie();
        for (string w : words) trie->insert(w);
        int n = s.size();
        vector<pair<int, int>> pairs;
        for (int i = 0; i < n; ++i) {
            Trie* node = trie;
            for (int j = i; j < n; ++j) {
                int idx = s[j];
                if (!node->children[idx]) break;
                node = node->children[idx];
                if (node->isEnd) pairs.push_back({i, j});
            }
        }
        if (pairs.empty()) return s;
        vector<pair<int, int>> t;
        int st = pairs[0].first, ed = pairs[0].second;
        for (int i = 1; i < pairs.size(); ++i) {
            int a = pairs[i].first, b = pairs[i].second;
            if (ed + 1 < a) {
                t.push_back({st, ed});
                st = a, ed = b;
            } else
                ed = max(ed, b);
        }
        t.push_back({st, ed});
        string ans = "";
        int i = 0, j = 0;
        while (i < n) {
            if (j == t.size()) {
                ans += s.substr(i);
                break;
            }
            st = t[j].first, ed = t[j].second;
            if (i < st) ans += s.substr(i, st - i);
            ans += "<b>";
            ans += s.substr(st, ed - st + 1);
            ans += "</b>";
            i = ed + 1;
            ++j;
        }
        return ans;
    }
};
type Trie struct {
	children [128]*Trie
	isEnd    bool
}

func newTrie() *Trie {
	return &Trie{}
}

func (this *Trie) insert(word string) {
	node := this
	for _, c := range word {
		if node.children[c] == nil {
			node.children[c] = newTrie()
		}
		node = node.children[c]
	}
	node.isEnd = true
}

func addBoldTag(s string, words []string) string {
	trie := newTrie()
	for _, w := range words {
		trie.insert(w)
	}
	n := len(s)
	var pairs [][]int
	for i := range s {
		node := trie
		for j := i; j < n; j++ {
			if node.children[s[j]] == nil {
				break
			}
			node = node.children[s[j]]
			if node.isEnd {
				pairs = append(pairs, []int{i, j})
			}
		}
	}
	if len(pairs) == 0 {
		return s
	}
	var t [][]int
	st, ed := pairs[0][0], pairs[0][1]
	for i := 1; i < len(pairs); i++ {
		a, b := pairs[i][0], pairs[i][1]
		if ed+1 < a {
			t = append(t, []int{st, ed})
			st, ed = a, b
		} else {
			ed = max(ed, b)
		}
	}
	t = append(t, []int{st, ed})
	var ans strings.Builder
	i, j := 0, 0
	for i < n {
		if j == len(t) {
			ans.WriteString(s[i:])
			break
		}
		st, ed = t[j][0], t[j][1]
		if i < st {
			ans.WriteString(s[i:st])
		}
		ans.WriteString("<b>")
		ans.WriteString(s[st : ed+1])
		ans.WriteString("</b>")
		i = ed + 1
		j++
	}
	return ans.String()
}
Try this approach in the editor

Complexity analysis

ApproachTimeSpaceWhen to Use
Brute Force Matching + Interval MergeO(n * k * L)O(n)Good for understanding the problem and when dictionary size is small
Boolean Marking with Longest MatchO(n * k * L)O(n)Clean implementation for interviews; avoids explicit interval merging
Trie-Based String MatchingO(n * L)O(W * L)Best when dictionary has many words with shared prefixes

Frequently asked questions

Is Add Bold Tag in String easy or hard?

Add Bold Tag in String is rated Medium difficulty. The main challenge is handling overlapping and adjacent matches correctly while constructing the final string. Once you recognize that all matches can be converted into merged intervals or a boolean marking array, the implementation becomes straightforward.

Add Bold Tag in String Python/Java solution

In Python or Java, iterate through the string and check each dictionary word using prefix matching such as startswith or substring comparison. Track the farthest bold boundary and mark characters in a boolean array. Finally, build the result by inserting <b> and </b> tags when transitioning between non-bold and bold regions.

How to solve Add Bold Tag in String in O(n)?

Near-linear performance can be achieved by building a Trie from all dictionary words and scanning the string while traversing the Trie for matching prefixes. Each character is processed while following possible matches up to the maximum word length L. This reduces redundant comparisons and results in O(n * L) time with O(W * L) space for the Trie structure.

What is the best approach for Add Bold Tag in String?

The boolean marking approach is typically the best balance of simplicity and efficiency. Iterate through the string, check if any dictionary word starts at each index, and track the farthest position that should remain bold. Mark characters in a boolean array and build the final string by opening and closing <b> tags when entering or leaving bold regions. Time complexity is O(n * k * L) where n is the string length, k is the number of words, and L is the maximum word length.

Is Add Bold Tag in String asked at Google/Amazon/Meta?

Add Bold Tag in String has appeared in interviews at companies that emphasize string manipulation and text processing, including Google and Facebook-style interview loops. The problem tests substring matching, interval merging, and careful string construction—skills frequently evaluated in mid-level algorithm interviews.

What data structure is used in Add Bold Tag in String?

Most solutions use arrays or interval lists to track which characters should be bold. A boolean array of length n is common for marking bold regions. For optimization, a Trie data structure can store dictionary words and enable efficient prefix-based string matching.

What is the time complexity of Add Bold Tag in String?

The common solution runs in O(n * k * L) time because for each position in the string you may check up to k words with length up to L. Space complexity is O(n) for the boolean array used to mark bold characters. A Trie-based optimization can reduce repeated prefix comparisons and achieve roughly O(n * L) matching time.

Comments

Now write it yourselfClose this page and solve Add Bold Tag in String in the editor, without looking.
Practise Add Bold Tag in String