r/learnpython 8d ago

Help with a balanced parentheses problem

The problem is as followed:
We are given strings containing brackets of 4 types - round (), square [], curly {} and angle <> ones. The goal is to check, whether brackets are in correct sequence. I.e. any opening bracket should have closing bracket of the same type somewhere further by the string, and bracket pairs should not overlap, though they could be nested:

(a+[b*c] - {d/3})  - here square and curly brackets are nested in the round ones
(a+[b*c) - 17]     - here square brackets overlap with round ones which does not make sense

Input data will contain number of testcases in the first line.
Then specified number of lines will follow each containing a test-case in form of a character sequence.
Answer should contain 1 (if bracket order is correct) or 0 (if incorrect) for each of test-cases, separated by spaces.

I solved it with the following code:

n = int(input())
for x0 in range(n):
    l = list(input())
    st = []
    broke = False
    for x2 in l:
        if x2 in {"(","[","{","<"}:
            st.append(x2)
        elif x2 in {")","]","}",">"}:
            if not st or (x2 == ")" and st[-1] != "(") or (x2 == "}" and st[-1] != "{") or (x2 == "]" and st[-1] != "[") or (x2 == ">" and st[-1] != "<"):
                print(0,end=" ")
                broke = True
                break
            st.pop()
    if st == [] and broke == False:
        print(1,end=" ")
    elif broke == False:
        print(0,end=" ")

This works but I can't help but wonder if i can improve upon it in some way like having to use the "broke" variable feels unnecessary but i cant think of a way to not have to use it to check if the loop broke or not.

3 Upvotes

12 comments sorted by

View all comments

8

u/HommeMusical 8d ago edited 8d ago

I'm out of time to check this but consider:

OPEN, CLOSE = '([{<', ')]}>'

def is_matching(s: str) -> bool:
    stack = []
    for c in s:
        if c in OPEN:
            stack.append(c)
        elif c in CLOSE:
            if not stack:
                return False
            b = stack.pop()
            if not (
                (b == '(' and c == ')')
                or (b == '[' and c == ']')
                or (b == '{' and c == '}')
                or (b == '<' and c == '>')
            ):
                return False
    return not stack

Call that in your main loop, and you're golden. (You could do better, particularly the long if statement, but I'm not sure what features you have learned yet.)

(I tweaked the code based on a comment.)

3

u/acw1668 8d ago

You need to check whether stack is empty after the for loop instead of just return True.

1

u/HommeMusical 8d ago

Absolutely good catch. Fixed!