π§ Cracking LeetCode's 'Valid Parentheses' with Kotlin
tl;dr: A journey toward clean code that not only works β but feels right

π§© The Problem: Valid Parentheses
One of the most common and deceptively simple problems on LeetCode is Valid Parentheses. The task is to check whether a given string of brackets β like ()[]{}
β is valid, meaning every opening bracket has a corresponding closing bracket in the correct order.
Itβs easy to understand, but solving it in a concise, readable, and safe way requires a bit of finesse. Especially when youβre doing it in Kotlin β a language that rewards elegant expression.
π€ My First Attempt: Functional but Flawed
My first Kotlin version got the job done logically, but there were small mistakes that showed up quickly:
val stack = ArrayDeque(listOf<String>())
Oops β I used String
instead of Char
, which was inefficient.
Then came a deeper issue: I only checked for closing brackets, but forgot to push opening brackets onto the stack. It worked for clean inputs but failed on edge cases β and even crashed on others.
These tiny issues reminded me that even for βeasyβ problems, attention to robustness matters just as much as logic.
π Debugging: Stack Safety and Map Logic
Through some trial and error (and a helpful reminder about stack.last()
throwing exceptions when empty), I refined the logic:
- Properly push opening brackets
- Safely pop from the stack using
removeLastOrNull()
- Use a
Map<Char, Char>
instead ofMap<String, String>
for memory and clarity
This version was getting close to idiomatic Kotlin β but it still wasnβt satisfying.
β¨ The Cleanest Version: Kotlin That Feels Right
After a few tweaks, I landed on a version that struck the perfect balance of safety, readability, and elegance:
What I loved about this version:
β
Uses Char
instead of String
β
Avoids crashes with removeLastOrNull()
β
Expressive map usage for bracket pairing
β
Clean for-in loop over .forEach
lambda
β
Zero clutter β just logic that reads like prose
π‘ What I Learned
Through this process, I picked up some valuable Kotlin idioms and best practices:
-
Use the Right Types: Using
Char
instead ofString
for single characters is more memory-efficient and semantically correct. -
Safe Operations: Kotlin provides safe alternatives like
removeLastOrNull()
that prevent runtime exceptions, making your code more robust. -
Expressive Collections: The
in
operator with maps makes code more readable than explicitcontains()
checks. -
Simplicity Wins: Sometimes a straightforward
for
loop is clearer than functional approaches like.forEach
. -
Early Returns: Using early returns with boolean expressions keeps the code flat and easy to follow.
β³ Time Complexity Analysis
- Iterating through the string β O(N)
- Stack operations (push/pop) β O(1)
- Overall Complexity: O(N) π (Linear time!)
π§ Key Insights
- A stack is the perfect data structure for this problem because of its LIFO (Last In, First Out) nature
- Mapping closing brackets to their opening counterparts simplifies the logic
- The solution is elegant because it handles all edge cases in a concise way
- Even βeasyβ problems deserve careful attention to code quality and safety
Letβs continue exploring elegant solutions to classic problems! If you have any questions or want to discuss other approaches to this problem, feel free to reach out.