Check for balanced parentheses in an expression O(1) space O(N^2) time complexity in Python

Checking for balanced parentheses is a classic programming problem. While the typical stack-based approach uses O(n) space, this article presents an O(1) space solution with O(n²) time complexity that modifies the string in-place by marking processed characters.

Algorithm Overview

The algorithm uses three global variables to track state and processes closing brackets by finding their matching opening brackets ?

  • cnt ? counts unmatched opening brackets
  • i ? current position in the string
  • j ? position of the last unmatched opening bracket

How It Works

When a closing bracket is found, the solve() function searches backward for its matching opening bracket. If found, both brackets are marked with '#' and the counters are updated ?

cnt = 0
i = 0
j = -1

def solve(s, temp):
    global i, j, cnt
    cnt -= 1
    s = list(s)
    if j > -1 and s[j] == temp:
        s[i] = '#'
        s[j] = '#'
        while j >= 0 and s[j] == '#':
            j -= 1
        i += 1
        return 1
    else:
        return 0

def bracketOrderCheck(s):
    global i, j, cnt
    if len(s) == 0:
        return True
    else:
        ans = False
        while i < len(s):
            if s[i] == '}':
                ans = solve(s, '{')
                if ans == 0:
                    return False
            elif s[i] == ')':
                ans = solve(s, '(')
                if ans == 0:
                    return False
            elif s[i] == ']':
                ans = solve(s, '[')
                if ans == 0:
                    return False
            else:
                j = i
                i += 1
                cnt += 1
        if cnt != 0:
            return False
        return True

# Reset global variables for fresh test
cnt = 0
i = 0  
j = -1
print(bracketOrderCheck("{([])}"))
True

Testing Different Cases

Let's test various bracket combinations to verify the algorithm ?

def reset_globals():
    global cnt, i, j
    cnt = 0
    i = 0
    j = -1

# Test cases
test_cases = [
    "{([])}",     # Balanced
    "([)]",       # Incorrectly nested
    "(((",        # Only opening brackets
    ")))",        # Only closing brackets
    "",           # Empty string
    "{[()]}",     # Complex balanced
]

for test in test_cases:
    reset_globals()
    result = bracketOrderCheck(test)
    print(f"'{test}' -> {result}")
'{([])}' -> True
'([)]' -> False
'(((' -> False
')))' -> False
'' -> True
'{[()]}' -> True

Algorithm Complexity

Aspect Complexity Reason
Time O(n²) Backward search for each closing bracket
Space O(1) Only uses global variables, no additional data structures

Limitations

This approach has significant limitations compared to the standard stack-based solution ?

  • Much slower O(n²) time complexity vs O(n) for stack approach
  • Uses global variables making it non-reentrant
  • Modifies the input string during processing

Conclusion

While this O(1) space approach demonstrates an alternative to stack-based solutions, the O(n²) time complexity makes it impractical for large inputs. The standard stack-based approach with O(n) time and space is preferred for most applications.

Updated on: 2026-03-25T10:03:00+05:30

542 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements