NLeetCode Solutions
ProblemsPatternsStatistics
© 2026 Created by Trịnh Minh Nhật
GitHubLeetCode
Related posts
  • 13. Roman to IntegerEasy
  • 14. Longest Common PrefixEasy
  • 49. Group AnagramsMedium
  • 125. Valid PalindromeEasy
  • 225. Implement Stack using QueuesEasy

20. Valid Parentheses

Easy
StringStack
Companies:
UberGoogleTwitterAirbnbAmazonFacebookZenefitsMicrosoftBloomberg
Answered: Dec 4, 2022
View on LeetCode

Problem Description

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.

Examples

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 &#39;()[]{}&#39;.

💡 Hints (3)


Solutions

Complexity Analysis

Time Complexity:O(n2)

Each replacement pass scans the entire string in O(n)O(n)O(n), and in the worst case (e.g., "(((...)))") we need O(n)O(n)O(n) passes to fully reduce the string, giving O(n2)O(n^{2})O(n2) overall.

Space Complexity:O(n)

Each string replacement creates a new string of up to O(n)O(n)O(n) characters.

The brute force approach repeatedly removes all adjacent matching pairs of brackets from the string until no more valid pairs remain. In each iteration, we replace (), [], and {} with empty strings; if the resulting string is eventually empty, all brackets were properly matched and nested. If the string is non-empty after no more replacements can be made, some brackets are unmatched or incorrectly ordered.

Complexity Analysis

Time Complexity:O(n)

We iterate through the string exactly once, performing O(1)O(1)O(1) hash map lookups and stack operations at each step.

Space Complexity:O(n)

In the worst case (all opening brackets, e.g., "((([[["), the stack holds up to n elements.

We use a stack and a hash map that maps each opening bracket to its expected closing bracket. As we iterate through the string, when we encounter an opening bracket, we push its corresponding closing bracket onto the stack. When we encounter a closing bracket, we check if it matches the top of the stack — if not, or if the stack is empty, the brackets are incorrectly nested and we return false. After processing all characters, the string is valid only if the stack is empty.

Complexity Analysis

Time Complexity:O(n)

We iterate through the string exactly once, performing O(1)O(1)O(1) hash map lookups and stack operations at each step.

Space Complexity:O(n)

In the worst case (all opening brackets, e.g., "((([[["), the stack holds up to n elements.

This approach is the inverted variant of Solution 2: instead of mapping opening brackets to expected closing brackets, we use a hash map that maps each closing bracket to its corresponding opening bracket, and push the actual opening brackets onto the stack. When we encounter a closing bracket, we check if the top of the stack is its matching opening bracket — if it matches we pop it, otherwise we return false. At the end, the string is valid only if the stack is empty.

Complexity Analysis

Time Complexity:O(n)

We iterate through the string exactly once, performing O(1)O(1)O(1) stack operations and constant-time conditional checks at each step.

Space Complexity:O(n)

In the worst case (all opening brackets, e.g., "((([[["), the stack holds up to n elements.

This approach stores opening brackets on the stack (as in Solution 3) but eliminates the hash map entirely by using explicit conditional checks to verify bracket pairs. When we encounter an opening bracket it is pushed onto the stack; when we encounter a closing bracket we pop the top and directly compare it against the expected opening bracket using a series of if conditions. The string is valid only if the stack is empty after all characters have been processed.

Conclusion

ApproachRatingTime ComplexitySpace ComplexityAdvantagesDisadvantages
Brute Force
O(n2)O(n^{2})O(n2)O(n)O(n)O(n)Simple to understand and implementInefficient — repeatedly scans the string, leading to O(n2)O(n^{2})O(n2) time
Stack store closing brackets
O(n)O(n)O(n)O(n)O(n)O(n)Classic interview approach; pushing the expected closing bracket makes the match check trivialRequires a hash map in addition to the stack
Stack store opening brackets
O(n)O(n)O(n)O(n)O(n)O(n)Hash map lookup only happens at closing brackets; slightly fewer stack operations on averageInverted map direction is slightly less intuitive to derive from scratch
Stack without hash map
O(n)O(n)O(n)O(n)O(n)O(n)No hash map needed — simpler memory footprintExplicit conditional checks are more verbose and harder to extend to new bracket types

Both Solution 2: Stack store closing brackets and Solution 3: Stack store opening brackets are optimal, both achieving O(n)O(n)O(n) time complexity and O(n)O(n)O(n) space complexity. The key difference is in the hash map direction: Solution 2 pushes the expected closing bracket onto the stack (so the check at each closing bracket is a direct equality), while Solution 3 pushes the actual opening bracket and looks up the match at closing time. Both are equally valid in interviews — Solution 2 is slightly more intuitive to explain, while Solution 3 more closely mirrors the natural reading of "does this closing bracket match what's on the stack?" Solution 4 achieves the same O(n)O(n)O(n) time complexity without a hash map but uses verbose conditional checks that are harder to extend.


Previous14. Longest Common Prefix
Next26. Remove Duplicates from Sorted Array
Related posts
  • 13. Roman to IntegerEasy
  • 14. Longest Common PrefixEasy
  • 49. Group AnagramsMedium
  • 125. Valid PalindromeEasy
  • 225. Implement Stack using QueuesEasy
On this page
7 lines
1class Solution:
2 def isValid(self, s: str) -> bool:
3 # Remove all pairs of valid parentheses until there are none left
4 while '()' in s or '[]' in s or '{}' in s:
5 s = s.replace('()', '').replace('[]', '').replace('{}', '')
6
7 return not s
22 lines
1class Solution:
2 def isValid(self, s: str) -> bool:
3 hash_map = {"(": ")", "{": "}", "[": "]"}
4
5 stack = []
6
7 for char in s:
8 if char in hash_map:
9 stack.append(hash_map[char])
10 else:
11 # If the stack is empty, it means there is no opening bracket for the current closing bracket
12 if not stack:
13 return False
14
15 top = stack.pop()
16
17 # If the top of the stack does not match the current closing bracket, it means the brackets are not properly nested
18 if top != char:
19 return False
20
21 # If the stack is empty at the end, it means all brackets are properly closed and nested
22 return not stack
18 lines
1class Solution:
2 def isValid(self, s: str) -> bool:
3 hash_map = {")": "(", "}": "{", "]": "["}
4
5 stack = []
6
7 for char in s:
8 if char in hash_map:
9 if stack and stack[-1] == hash_map[char]:
10 # If the current character is a closing bracket, we check if the top of the stack is the corresponding opening bracket. If it is, we pop the top of the stack. If it isn't, or if the stack is empty when we encounter a closing bracket, then the string is not valid.
11 stack.pop()
12 else:
13 return False
14 else:
15 # If the current character is an opening bracket, we push it onto the stack
16 stack.append(char)
17
18 return not stack
23 lines
1class Solution:
2 def isValid(self, s: str) -> bool:
3 stack = []
4
5 for char in s:
6 if char in "([{":
7 # Stack store the opening brackets
8 stack.append(char)
9 else:
10 if not stack:
11 return False
12
13 open_bracket = stack.pop()
14
15 # Check if the closing bracket matches the last opening bracket
16 if (
17 (char == ")" and open_bracket != "(")
18 or (char == "]" and open_bracket != "[")
19 or (char == "}" and open_bracket != "{")
20 ):
21 return False
22
23 return not stack