Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions problems/0020-valid-parentheses/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# 0020. Valid Parentheses

[LeetCode Link](https://leetcode.com/problems/valid-parentheses/)

Difficulty: Easy
Topics: String, Stack, Bracket Sequences
Acceptance Rate: 45.1%

## Hints

### Hint 1

Think about the order in which brackets must be closed. When you see a closing bracket, which opening bracket must it match: the first one you saw, or the most recent one that hasn't been closed yet? What data structure naturally gives you "the most recent unmatched item"?

### Hint 2

Use a **stack**. Opening brackets go onto the stack. A closing bracket has to match whatever is on top of the stack right now.

### Hint 3

For each closing bracket, check that the stack is non-empty **and** that its top is the matching opener. If so, pop it. If not, the string is invalid right away. When you reach the end, the string is valid only if the stack is **empty**, because leftover openers were never closed. A map from closing to opening bracket keeps the matching check short.

## Approach

Brackets nest. The innermost open bracket has to close first, which is Last-In-First-Out behavior, so a stack fits.

1. Build a lookup `pairs` that maps each closing bracket to its opener: `')' -> '('`, `']' -> '['`, `'}' -> '{'`.
2. Go through the string one character at a time:
- If the character is an opening bracket, push it onto the stack.
- If it is a closing bracket:
- If the stack is empty, there is nothing to match it with. Return `false`.
- If the top of the stack is not `pairs[c]`, the brackets are interleaved or of the wrong type. Return `false`.
- Otherwise pop the top. This pair is matched.
3. After the loop, return `true` only if the stack is empty.

**Example:** `s = "([)]"`

| char | action | stack |
|------|-----------------|--------|
| `(` | push | `(` |
| `[` | push | `( [` |
| `)` | top is `[`, need `(`, so mismatch | return false |

**Example:** `s = "([])"`

| char | action | stack |
|------|--------------------|--------|
| `(` | push | `(` |
| `[` | push | `( [` |
| `]` | top `[` matches, pop | `(` |
| `)` | top `(` matches, pop | empty |

The stack ends empty, so the result is `true`.

**Small optimization:** a valid string always has even length, so an odd-length input can return `false` immediately.

## Complexity Analysis

Time Complexity: O(n). Each character is pushed and popped at most once.
Space Complexity: O(n). In the worst case the stack holds every character, for example `"(((((("`.

## Edge Cases

- **Only closing brackets** (`"]"`, `"))"`): the stack is empty when a closer arrives. Check for this before reading the top, or you will index out of range.
- **Only opening brackets** (`"(("`, `"{"`): no closer ever fails, but the stack is not empty at the end. You need the final emptiness check.
- **Odd length** (`"(()"`): this can never be valid, so the length check is a cheap early exit.
- **Interleaved brackets** (`"([)]"`): the counts of each type are balanced, but the order is wrong. This is why separate counters for each type don't work and a stack is needed.
- **Deep nesting** (`"{[()]}"`): makes sure the stack correctly handles several levels.
- **Opens after a matched prefix** (`"()("`): the early part matches, but the final check still catches the leftover opener.
68 changes: 68 additions & 0 deletions problems/0020-valid-parentheses/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
number: "0020"
frontend_id: "20"
title: "Valid Parentheses"
slug: "valid-parentheses"
difficulty: "Easy"
topics:
- "String"
- "Stack"
- "Bracket Sequences"
acceptance_rate: 4505.6
is_premium: false
created_at: "2026-10-01T06:18:26.535875+00:00"
fetched_at: "2026-10-01T06:18:26.535875+00:00"
link: "https://leetcode.com/problems/valid-parentheses/"
date: "2026-10-01"
---

# 0020. Valid Parentheses

Given a string `s` containing just the characters `'('`, `')'`, `'{'`, `'}'`, `'['` and `']'`, determine if the input string is valid.

An input string is valid if:

1. Open brackets must be closed by the same type of brackets.
2. Open brackets must be closed in the correct order.
3. Every close bracket has a corresponding open bracket of the same type.





**Example 1:**

**Input:** s = "()"

**Output:** true

**Example 2:**

**Input:** s = "()[]{}"

**Output:** true

**Example 3:**

**Input:** s = "(]"

**Output:** false

**Example 4:**

**Input:** s = "([])"

**Output:** true

**Example 5:**

**Input:** s = "([)]"

**Output:** false



**Constraints:**

* `1 <= s.length <= 104`
* `s` consists of parentheses only `'()[]{}'`.
34 changes: 34 additions & 0 deletions problems/0020-valid-parentheses/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

// Approach: Stack.
// Push every opening bracket. For a closing bracket, the top of the stack
// must be its matching opener; otherwise the string is invalid. The string
// is valid only if the stack is empty at the end.
// Time: O(n), Space: O(n).
func isValid(s string) bool {
if len(s)%2 == 1 {
return false
}

pairs := map[byte]byte{
')': '(',
']': '[',
'}': '{',
}

stack := make([]byte, 0, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
open, isClose := pairs[c]
if !isClose {
stack = append(stack, c)
continue
}
if len(stack) == 0 || stack[len(stack)-1] != open {
return false
}
stack = stack[:len(stack)-1]
}

return len(stack) == 0
}
34 changes: 34 additions & 0 deletions problems/0020-valid-parentheses/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import "testing"

func TestSolution(t *testing.T) {
tests := []struct {
name string
input string
expected bool
}{
{"example 1: single pair", "()", true},
{"example 2: consecutive pairs of each type", "()[]{}", true},
{"example 3: mismatched types", "(]", false},
{"example 4: nested pairs", "([])", true},
{"example 5: interleaved pairs", "([)]", false},
{"edge case: single opening bracket", "(", false},
{"edge case: single closing bracket", "]", false},
{"edge case: only closing brackets", "))", false},
{"edge case: only opening brackets", "((", false},
{"edge case: closer before opener", ")(", false},
{"edge case: deep nesting", "{[()]}", true},
{"edge case: unclosed opener after valid prefix", "()((", false},
{"edge case: mixed nesting and sequence", "{[]}([]){}", true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isValid(tt.input)
if result != tt.expected {
t.Errorf("isValid(%q) = %v, want %v", tt.input, result, tt.expected)
}
})
}
}