Write overlapping text styles with the fewest tags

Write codeHard40 min

Your task

Your editor stores formatting as ranges over the text: bold from 3 to 9, italic from 5 to 12, and so on. To send a message as email, it writes HTML with <b>, <i>, <u> and <s> tags. Tags must nest properly, so a range that crosses another one has to be written as more than one tag. Email clients cut off long messages, so you want as few tags as possible.

Write fewest_tags(length, ranges) that returns the smallest number of elements the HTML needs.

Input and output:

  • length: the number of characters in the text, from 0 to 100,000.
  • ranges: up to 1,000 ranges, each [style, start, end]. style is "b", "i", "u" or "s". The range covers characters start to end - 1, where 0 <= start < end <= length. Ranges of the same style may overlap or touch.
  • Returns an integer.

Rules:

  • A character has a style when at least one range of that style covers it.
  • An element is an opening tag, the characters inside it, and the matching closing tag. Each element has one style.
  • Every character must be inside exactly one element of each style it has, and inside no element of a style it does not have.
  • Elements nest properly: when 2 elements share a character, one of them lies entirely inside the other.
  • Return the smallest number of elements that meets these rules.

Examples

fewest_tags(length: int, ranges: list[list]) -> int
Example 1
Inputfewest_tags(12, [["b", 3, 9], ["i", 5, 12]])
Output3
Example 2
Inputfewest_tags(10, [["b", 0, 10], ["i", 2, 4], ["i", 6, 8]])
Output3
Example 3
Inputfewest_tags(8, [["u", 0, 5], ["b", 2, 8], ["i", 4, 6]])
Output5