Fewest block tags that repair a broken template

Write codeHard40 min

Your task

Your team writes Svelte-style templates, where blocks open and close with tags such as {#if} and {/if}. A bad merge sometimes leaves a template whose blocks cross or never close. The template linter then suggests a fix that adds as few block tags as possible.

Write fewest_added_tags(tags) that returns the smallest number of block tags the fix has to add.

Input and output:

  • tags: the template's block tags in order, up to 200 of them. Each is one of "{#if}", "{/if}", "{#each}", "{/each}", "{#await}", "{/await}", "{#key}" and "{/key}". The rest of the template is left out.
  • Returns an integer.

Rules:

  • {#name} opens a block, and {/name} closes a block with the same name.
  • A sequence of tags nests properly when every tag can be paired with another so that no 2 pairs cross. Each pair is an opening tag and a later closing tag of the same name.
  • Pairs cross when exactly 1 tag of one pair lies between the 2 tags of the other.
  • The fix may add tags anywhere: before the first tag, after the last one, or between any 2 tags. It may not remove or move a tag.
  • Return the smallest number of added tags that makes the whole sequence nest properly.

Examples

fewest_added_tags(tags: list[str]) -> int
Example 1
Inputfewest_added_tags(["{#if}", "{#each}", "{/if}", "{/each}"])
Output2
Example 2
Inputfewest_added_tags(["{#each}", "{#if}", "{/if}", "{#await}"])
Output2
Example 3
Inputfewest_added_tags(["{#if}", "{/if}", "{#key}", "{#each}", "{/each}", "{/key}"])
Output0