Walk a string of bracket characters. Push every opening bracket. On a closing bracket, pop and verify it matches; mismatch or empty-stack pop means unbalanced. At end of string, stack must be empty.

Algorithm

Canonical input "({[]})" (balanced) finishes with the stack empty and the result true.

Basic Implementation

basic.kt
fun matchOpen(close: Char): Char = when (close) {
	')' -> '('
	']' -> '['
	'}' -> '{'
	else -> ' '
}

fun main() {
	val text = "({[]})"
	val stack = ArrayDeque<Char>()
	var balanced = true
	for (i in text.indices) {
		val ch = text[i]
		if (ch == '(' || ch == '[' || ch == '{') {
			stack.addLast(ch)
		} else {
			if (stack.isEmpty() || stack.last() != matchOpen(ch)) {
				balanced = false
				break
			}
			stack.removeLast()
		}
	}
	if (stack.isNotEmpty()) {
		balanced = false
	}
	println(if (balanced) "True" else "False")
}

Complexity

  • Time: O(n)
  • Space: O(n) worst case

Implementation notes

  • Kotlin: ArrayDeque<Char> with addLast / removeLast / last() is the smallest honest stack shape; the stdlib already exposes a proper deque so the lesson can stay on the explicit push/pop pattern instead of leaning on a generic MutableList<Char>.
  • The matchOpen helper documents the closing -> opening map without leaking runtime references into the replay.
  • The replay highlights the current character, shows the stack updating each frame, and surfaces the final balanced/unbalanced verdict.
stack push/pop Use an `ArrayDeque<Char>` as the open-bracket stack; push by `stack.addLast(ch)`, pop by `stack.removeLast()`.
matching map A small `matchOpen(close)` helper returns the expected opener for each closing bracket — three explicit `when` arms keep the lesson compact.