Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 8 – Stacks and monotonic stacks

Bracket matching and minimum fixes

Check that brackets of three kinds are balanced in one pass with a stack, then count the fewest insertions or removals that balance a string.

  • Beginner
  • 25 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 25 minutes free
Free: Deleting matched pairs is right, but slow on deep nesting · One pass with a stack finds the first problem · For one kind of bracket, a counter gives the fewest fixes · Practise: count the fewest fixes. With a pass: 3 in-depth parts and 3 interview answers, about 18 minutes.

What you will learn

  • Check a text with (), [] and {} in one pass with a stack, and say why it takes O(n) time
  • Report where a text first breaks, and in which unit each of 14 languages counts that position
  • Count the fewest insertions or removals that balance one kind of bracket, and prove the count
  • Explain why mixed kinds of bracket need a dynamic program, and test a checker against a brute force

Before you start

What you’ll learn · Before you start

What you will learn

  • Check a text with (), [] and {} in one pass with a stack, and say why it takes O(n) time
  • Report where a text first breaks, and in which unit each of 14 languages counts that position
  • Count the fewest insertions or removals that balance one kind of bracket, and prove the count
  • Explain why mixed kinds of bracket need a dynamic program, and test a checker against a brute force

Before you start

On this page

Bracket matching checks that every opening bracket in a text is closed by its own kind, in the right order: {[()]} is balanced, while ([)] and (() are not. One pass with a stack does it. Push each opener; when a closer arrives, the opener on top of the stack must be its partner, and it is popped; at the end nothing may be left open. That takes O(n) time for n characters. Minimum fixes is the question that comes next: the fewest brackets to insert or remove so that a text becomes balanced. For one kind of bracket, a counter in the same pass answers it. Below are an original version of both problems, a brute force too slow at their limits, and the one-pass ideas worked through examples.

Deleting matched pairs is right, but slow on deep nesting

The problem

A messaging service fills in templates such as Hi {name}, order [#{id}] ships (in {days} days) before it sends them. A template may be saved only if its brackets are balanced: every (, [ and { is closed later by its own kind, ), ] or }, and a bracket opened inside another one is closed before it. Every other character is text. Return True for a balanced template and False otherwise. A template has at most 1,000,000 characters.

The code in this lesson is checked on these three templates:

  1. Hi {name}, order [#{id}] ships (in {days} days) is balanced.
  2. Total: {sum(a[i)]} is not: the ) at position 15 tries to close the ( while the [ opened after it is still open.
  3. (see [note 3] is not: the ( at position 0 is never closed.

The brute force: delete matched pairs until none is left

Drop the text, then delete every adjacent pair (), [] or {}, and repeat until a round deletes nothing. The template is balanced exactly when nothing is left. That is easy to trust but slow: on a template nested d brackets deep, only the innermost pairs are ever adjacent, so each round deletes a pair or two while it reads all the rest of the text, round after round.

Delete adjacent pairs, round after round Python · brute/brute_force.py
"""The brute force: delete adjacent matched pairs, (), [] and {}, until none is left."""
import time

PAIRS = ("()", "[]", "{}")


def balanced_brute(template):
    """True when every bracket is closed by its own kind, in nested order; also how many characters it read."""
    s = "".join(ch for ch in template if ch in "()[]{}")  # the text between brackets does not matter
    read = 0
    while True:
        shorter = s
        for pair in PAIRS:
            read += len(shorter)  # each replace() reads the whole string
            shorter = shorter.replace(pair, "")
        if shorter == s:  # no adjacent pair left to delete
            return s == "", read
        s = shorter


for template in ["Hi {name}, order [#{id}] ships (in {days} days)", "Total: {sum(a[i)]}", "(see [note 3]"]:
    print(f"{template!r}: {balanced_brute(template)[0]}")


def nested(depth):
    """depth openers of mixed kinds, then their closers: one pair can go per round."""
    openers = "([{" * (depth // 3 + 1)
    closers = {"(": ")", "[": "]", "{": "}"}
    head = openers[:depth]
    return head + "".join(closers[ch] for ch in reversed(head))


per_char = 0.0
for depth in (5_000, 10_000, 20_000):
    template = nested(depth)
    best = float("inf")
    for _ in range(3):  # the fastest of three runs: the least disturbed by other programs
        start = time.perf_counter()
        ok, read = balanced_brute(template)
        best = min(best, time.perf_counter() - start)
    assert ok
    per_char = best / read
    print(f"depth {depth:,} ({len(template):,} characters): {read:,} characters read in {best * 1000:,.0f} ms")

# At the limit, nested 500,000 deep: 25 times the depth of the last run, so about 625 times the characters.
read *= (500_000 // 20_000) ** 2
print(f"depth 500,000 (1,000,000 characters): about {read / 1e9:,.0f} billion characters, {read * per_char / 60:,.0f} minutes at that speed")

Output

'Hi {name}, order [#{id}] ships (in {days} days)': True
'Total: {sum(a[i)]}': False
'(see [note 3]': False
depth 5,000 (10,000 characters): 50,010,000 characters read in 33 ms
depth 10,000 (20,000 characters): 200,000,000 characters read in 564 ms
depth 20,000 (40,000 characters): 800,040,000 characters read in 1,439 ms
depth 500,000 (1,000,000 characters): about 500 billion characters, 15 minutes at that speed

This output changes from run to run: the times depend on the computer and on what else it is doing

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

Each doubling of the depth reads four times as many characters, as an O(n²) method should; the times follow, unevenly, because other programs disturb them. At the limit of a million characters, nested half a million deep, that is about 500 billion characters, many minutes of work where the time limit allows about a second.

What to notice

Look at what each round deletes: a closer and the nearest opener before it that is still there. So a closer always belongs to the most recent opener that is still open, which is the stack cue of the module overview.

Checkpoint

Check: Deleting matched pairs, and what it costs

  1. Question 1 of 2 The brute force read 200,000,000 characters at depth 10,000. About how many does it read at depth 20,000?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: About 800 million

    On deep nesting each round deletes a pair or two and reads the rest of the text, so the work is about the depth times the length. The recorded run read 800,040,000 characters at depth 20,000, four times the 200,000,000 of depth 10,000.

  2. Question 2 of 2 Each round of the brute force deletes an adjacent pair such as (). Which opener does a closer pair with in the end?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The most recent opener before it that is still open

    An adjacent pair can be deleted only when nothing stands between the opener and the closer, so every closer ends up with the most recent opener that is still open. That observation is what the one-pass stack uses.

One pass with a stack finds the first problem

Read the template once, from left to right, and keep the open brackets on a stack:

  1. Skip text characters, and push every opener.
  2. At a closer, look at the top. If nothing is open, or the top is not its partner, the template is not balanced, and this closer is its first problem. Otherwise pop the top.
  3. At the end, the template is balanced only if the stack is empty. If it is not, the opener at the bottom is the earliest one that was never closed.

Each character costs at most one push or one pop, so the check takes O(n) time, and O(n) memory when every bracket is open at once. The diagram follows the second example to its first problem.

The stack while Total: {sum(a[i)]} is checked: three openers are pushed, then ) at position 15 meets [ on top, so the check stops there.Start: nothing is open{ at 7: push( at 11: push[ at 13: push) at 15: the top is [, not (the first problem is at 15{ (7){ (7)( (11){ (7)( (11)[ (13)compare with the top

A closer must match the newest open bracket

Text description of the diagram

The diagram shows the stack of open brackets after each bracket of the template Total: {sum(a[i)]}, from top to bottom. The text between the brackets changes nothing and is not drawn. The newest open bracket, the top of the stack, has a thick border.

  1. At the start nothing is open, and the stack is empty.
  2. The { at position 7 is pushed: the stack holds { from position 7.
  3. The ( at position 11 is pushed: the stack holds { and (, with ( on top.
  4. The [ at position 13 is pushed: the stack holds {, ( and [, with [ on top.
  5. The ) at position 15 is compared with the top. The top is [, and the partner of ) is (, so they do not match.

The check stops at position 15: the closing ) tries to close the ( while the [ opened after it is still open, so the brackets cross. That position is the first problem in the template.

Step through the same template, or type one of your own:

Interactive · step through it The one-pass check on Total: {sum(a[i)]} Opening brackets wait on the stack; each closing bracket must match the top.
Stack, bottom to top: empty. Reading "Total: {sum(a[i)]}", at character 0.Total:␣{sum(a[i)]}empty
  • being compared or looked at
  • being moved or written

Pseudo-code

  1. for each character c:
  2. if c opens a bracket: push c
  3. if c closes a bracket:
  4. if the stack is empty or its top does not match c: return "not balanced"
  5. pop
  6. return the stack is empty ? "balanced" : "not balanced"

Check whether the brackets in "Total: {sum(a[i)]}" are balanced. Each opening bracket waits on a stack; each closing one must match the most recent opening one still waiting.

When it finishes: Not balanced.

Stack size 0
Characters read 0

The third example ends with a bracket still open:

Bracket Step Still open
( at 0 push ( at 0
[ at 5 push ( at 0, [ at 5
] at 12 the top is [: pop ( at 0
the end the stack is not empty the problem is at 0

Checkpoint

Check: One pass with a stack of open brackets

  1. Question 1 of 2 The one-pass check reads the template ([)]. Where does it report the first problem?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: At position 2, the )

    After ( and [ the stack holds both, with [ on top. The ) at position 2 must close the newest open bracket, which is [, so the check stops there. Each kind has as many closers as openers, but the brackets cross.

  2. Question 2 of 2 Why must a closer match the bracket on top of the stack, rather than any open bracket of its kind?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Brackets nest, so the bracket opened last must be closed first

    In a balanced text, a bracket opened inside another one closes before the outer one does. The newest bracket that is still open is therefore the only one the next closer may close, and that bracket is the top of the stack.

JSON Validator JSON is bracket matching with [ ] and { } plus quoted strings. Paste a document and see where its brackets break.

For one kind of bracket, a counter gives the fewest fixes

A formula with only round brackets raises the second question: what are the minimum fixes, the fewest brackets to insert or remove, that balance it? A counter replaces the stack, because every open bracket is the same. Read from the left and count the ( still open. A ) closes one of them; a ) that arrives when the count is 0 has no partner and needs one fix. At the end, every ( still open needs one fix too. So the minimum is the closers without a partner plus the openers never closed, for insertions and removals alike.

In ())((, the ) at position 2 has no partner and two ( stay open, so three fixes are needed: insert brackets to get ()()(()), or remove positions 2, 3 and 4 to keep (). Step through the count:

Interactive · step by step Counting the fewest fixes of ())(( in one pass Step through the five brackets. The two counts change by one at a time, and their sum at the end is the answer.
Counting the fewest fixes of ())(( in one pass, step 7 of 7. Showing Bracket read (end of the string), Still open (2), Closers without partner (1), Fewest fixes (1 + 2 = 3). In focus: Fewest fixes.Bracket readend of the stringStill open2Closers without partner1Fewest fixes1 + 2 = 3

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. Start. Nothing has been read, so nothing is open and no closer is waiting for a partner.
  2. ( at 0. An opener raises the open count to 1.
  3. ) at 1. A closer with something open closes one opener, so the open count falls back to 0.
  4. ) at 2. This closer finds nothing open: it has no partner, so it needs one fix. The count of such closers becomes 1.
  5. ( at 3. An opener raises the open count to 1.
  6. ( at 4. Another opener raises the open count to 2.
  7. The end. Each of the 2 brackets still open needs a closer, and the 1 lonely closer needs an opener: 1 + 2 = 3 fixes, inserted or removed.

Mixed kinds need more than a counter. Two natural greedy rules, closing the top early or skipping a closer that does not match, each give wrong counts, and a A method that solves a problem from the answers to its smaller pieces, each worked out once and stored. Here the pieces are the stretches of the string, and the answer is the fewest fixes of each. over the pieces of the string gives the right count in O(n³).

Checkpoint

Check: The fewest fixes for one kind of bracket

  1. Question 1 of 2 How many brackets must be inserted, at the least, to balance the formula ))(( ?

    Type a number.

    A hint

    Count the closers that find nothing open, then the openers still open at the end.

    Show the answer: Question 1 of 2

    Answer: 4 brackets

    Reading from the left, both ) arrive when nothing is open, so each needs an inserted ( before it. Both ( are still open at the end, so each needs an inserted ). That is 2 + 2 = 4, for example ()()()() after inserting (, (, ) and ).

  2. Question 2 of 2 For a string of round brackets only, what does the one-pass count keep between characters?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: How many ( are still open, and how many ) found nothing open

    With one kind of bracket every open bracket is alike, so a count replaces the stack: a ( adds one, a ) takes one away or, when nothing is open, counts as a closer without a partner.

Practise: count the fewest fixes

Exercise · Easy · Python

Count the fewest brackets that balance a formula

A formula editor accepts only round brackets. Write min_fixes(s), which returns the fewest brackets that must be inserted into s to make every ( closed by a later ) and every ) close an earlier (.

  • s holds only the characters ( and ), and it may be empty. It has at most 1,000,000 characters.
  • Inserting a bracket may happen anywhere: before the first character, between two characters or after the last.
  • Return a number, not the fixed string.
min_fixes("())((")  # 3: one ")" has no partner, and two "(" are never closed
min_fixes("(()")    # 1
min_fixes(")(")     # 2

Work one more example by hand before you code: a string that starts with three closers.

Starter code · fixes.py

def min_fixes(s):
    """The fewest brackets to insert so that every bracket of s has a partner."""
    # Replace this line with your code.
    return 0
The sample tests · test_fixes.py
import random
import sys

from fixes import min_fixes

LINE_LIMIT = 4_000_000


def trusted(s):
    """A slow reference the tests trust: delete "()" pairs until none is left; every bracket left needs one fix."""
    while "()" in s:
        s = s.replace("()", "")
    return len(s)


class TooSlow(Exception):
    pass


def run_limited(s):
    """Call min_fixes, stopped after LINE_LIMIT executed lines (a fair time limit)."""
    executed = 0

    def count_lines(frame, event, arg):
        nonlocal executed
        if event == "line":
            executed += 1
            if executed > LINE_LIMIT:
                raise TooSlow
        return count_lines

    sys.settrace(count_lines)
    try:
        return min_fixes(s)
    except TooSlow:
        raise AssertionError(f"too slow: more than {LINE_LIMIT:,} lines ran; aim for one pass") from None
    finally:
        sys.settrace(None)


def test_examples():
    """the examples from the prompt"""
    assert min_fixes("())((") == 3
    assert min_fixes("(()") == 1
    assert min_fixes(")(") == 2


def test_nothing_to_fix():
    """an empty formula and balanced ones"""
    assert min_fixes("") == 0
    assert min_fixes("()") == 0
    assert min_fixes("(())()") == 0


def test_only_one_kind_of_bracket():
    """only openers, or only closers"""
    assert min_fixes("(((") == 3
    assert min_fixes(")))") == 3


def test_closers_first():
    """closers that come before any opener"""
    assert min_fixes("))((") == 4
    assert min_fixes("))()") == 2


def test_random_formulas():
    """200 random formulas against the slow reference"""
    rng = random.Random(7)
    for _ in range(200):
        s = "".join(rng.choice("()") for _ in range(rng.randrange(12)))
        assert min_fixes(s) == trusted(s), s


def test_long_formula():
    """a formula of 200,000 brackets, checked against a line limit"""
    s = ")" * 1_000 + "()" * 99_000 + "(" * 1_000
    assert run_limited(s) == 2_000
A hint

Read the string once, from left to right, and keep one number: how many ( are still open. What should happen to that number at a ), and what does a ) mean when the number is already 0? Whatever is still open at the end needs fixing too.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

These questions start with the idea you know least.

Practice that adapts to you

Practise this lesson

9 questions about 10 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 9 Why is deleting adjacent matched pairs slow on a deeply nested template?

    Choose one answer.

    Show the answer: Question 1 of 9

    Answer: Each round deletes only the innermost pair or two, yet reads the whole rest of the text

    A template nested d deep needs on the order of d rounds, and each round reads up to n characters, so the work grows like d × n, about n²/2 at the deepest.

  2. Question 2 of 9 How does the brute force's work grow on a template nested d brackets deep?

    Choose one answer.

    Show the answer: Question 2 of 9

    Answer: Like d × n, which is about n²/2 for a template of n brackets nested as deep as it can be

    On a deeply nested template only the innermost pairs are adjacent, so each round deletes a pair or two and reads the rest of the text. With d = n/2, doubling the length multiplies the characters read by four.

  3. Question 3 of 9 A template of 1,000,000 characters is nested 500,000 deep. Is the brute force acceptable within a one-second limit?

    Choose one answer.

    Show the answer: Question 3 of 9

    Answer: No, it reads about 500 billion characters, many minutes of work

    About d × n = 500,000 × 1,000,000, or 500 billion characters read, so the method fails at the limit, and one pass with a stack is needed.

  4. Question 4 of 9 What does the one-pass check do at a closer when nothing is open?

    Choose one answer.

    Show the answer: Question 4 of 9

    Answer: It reports this closer as the first problem

    An empty stack at a closer means the closer has no opener to meet, so the check stops and reports its position.

  5. Question 5 of 9 At which position does the one pass report the first problem of {(a])} ?

    Type a number.

    A hint

    Push the openers, and compare each closer with the top.

    Show the answer: Question 5 of 9

    Answer: 3

    { at 0 and ( at 1 are pushed, a at 2 is text, and the ] at 3 meets ( on top, which is not its partner.

  6. Question 6 of 9 Which template of 1,000,000 characters makes the stack of the one pass largest?

    Choose one answer.

    Show the answer: Question 6 of 9

    Answer: 500,000 openers followed by their 500,000 closers

    The stack holds the brackets open at the same moment, so its largest size is the deepest nesting: half the length when every opener comes before every closer.

  7. Question 7 of 9 In the counter for one kind of bracket, what does a ) do when the count of open brackets is 0?

    Choose one answer.

    Show the answer: Question 7 of 9

    Answer: It counts as a closer without a partner, which needs one fix

    A ) that finds nothing open needs a fix of its own. At the end the fewest fixes are these closers plus the openers still open.

  8. Question 8 of 9 How many fixes, inserted or removed, does )(()( need?

    Type a number.

    A hint

    Track the brackets still open and the closers without a partner.

    Show the answer: Question 8 of 9

    Answer: 3 fixes

    The first ) has no partner (1). Then (, ( and ) leave one open, and the last ( makes two open: 1 + 2 = 3.

  9. Question 9 of 9 A single counter for ( and [ together reports 0 fixes for (]. Why is that wrong?

    Choose one answer.

    Show the answer: Question 9 of 9

    Answer: It ignores the kinds, so it lets ] close (, and the text needs 2 fixes

    A counter works for one kind of bracket only. With several kinds the order of kinds matters, which is why mixed kinds need more than a counter.

The one-pass check in 14 languages, with its proof Pro: opens with a Pro, Premium or Ultimate pass

The check takes a dozen lines in every language, and each language counts positions in its own unit. Here it is in 14 languages with their recorded runs, the invariant that proves the stack right, and a stress test that catches two plausible slips.

In this part:

  • The check in 14 languages, each counting positions its own way
  • Why a closer may close only the top: the invariant and its proof
  • Two slips, caught by a stress test

2 runnable examples (Python) · about 12 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Fewest insertions and removals: proved, rebuilt and checked Pro: opens with a Pro, Premium or Ultimate pass

The counter gives a number. This part proves that no smaller fix exists, rebuilds the fixed text both ways, and shows why two or more kinds of bracket need a dynamic program instead of a greedy rule.

In this part:

  • Why the counter’s count is the minimum: a proof with prefix balances
  • Two or more kinds: two greedy rules fail, reproduced, and a dynamic program

2 runnable examples (Python) · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Edge cases, variants and follow-ups, with measured numbers Pro: opens with a Pro, Premium or Ultimate pass

A check that is right can still be slow, fail on deep input or hold more memory than it needs. This part measures the one pass at its limit, compares the four methods, and answers the variants and follow-up questions that interviews add.

In this part:

  • Measured: a million characters, the stack’s memory and the recursion limit
  • Checking and fixing side by side: two trade-off tables
  • Edge cases and common bugs
  • Variants, with answers
  • Follow-up questions, answered

1 runnable example (Python) · about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

  1. Fresher to mid · Warm-up

    When is a counter enough to check brackets, and when do you need a stack?

    A counter is enough when there is only one kind of bracket. Count the openers still open: an opener adds one, a closer takes one away, the count must never drop below zero, and it must end at zero. With two or more kinds, counting each kind on its own is not enough, because it ignores order: ([)] has one opener and one closer of each kind, and no count ever drops below zero, yet the brackets cross. A closer must match the most recent opener that is still open, and only a stack remembers which one that is. The memory differs too: a counter needs O(1), while a stack holds every bracket that is open at once, O(n) in the worst case.

  2. Mid to senior

    A code editor must underline the first bracket that breaks a file of up to 20 MB, and update the underline within 16 ms of every keystroke. A full rescan is too slow. What do you store, and what does one edit cost?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A candidate counts the fewest insertions that balance a string of (), [] and {} with a stack: when a closer does not match the top, insert the top's closer. Give an input where this is wrong, a correct method, and its cost for a string of 500 characters.

    Model answer, Pro. First step and follow-ups

  4. Fresher to mid

    A spreadsheet formula uses only round brackets. Remove the fewest brackets so that it becomes valid, and return the result. Explain why no smaller fix exists, and how your answer changes when the formula has 10⁷ characters and memory is tight.

    Model answer, Pro. First step and follow-ups

Two changes an interviewer might make to the problem:

Checkpoint

Interview round: two follow-up questions

  1. Question 1 of 2 The interviewer changes the input: only round brackets, arriving as a stream of 10⁹ characters that cannot be stored. What do you keep?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Two counts, the brackets still open and the closers without a partner, so the memory is O(1)

    The counter of the fewest-fixes section needs O(1) memory whatever the length, which is why it fits a stream.

  2. Question 2 of 2 For the template (see [note 3], the interviewer asks which position an editor should underline. What does the one pass report?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Position 0, the earliest opener that was never closed

    The ] at 12 closes the [ at 5, and the ( at 0 stays open to the end, so the check reports position 0, as the table of the third example shows.

Key takeaways

  • Bracket matching is one pass with a stack of open brackets: a closer must match the top, and nothing may be left open at the end.
  • The brute force, deleting adjacent pairs round after round, is O(n²) on deep nesting: minutes at a million characters.
  • For one kind of bracket, the minimum fixes are the closers without a partner plus the openers never closed, and a counter finds them in the same pass.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.