Inspired by @AviFS.
Given a string containing brackets, e.g.
You can parse through it with a stack of brackets. When you find an open bracket, push a value to the stack, when you find a close bracket, pop from the stack. If you make these values indices, you know where you need to remove brackets.
If you try to pop from an empty stack, the close bracket is unmatched, and the brackets left on the stack at the end are unmatched.
For example, the above would be:
[ # PUSH index 1 -  xyz] # POP -  ] # POP from empty stack, unmatched abc[ # PUSH index 4 -  [ # PUSH index 5 - [4, 5] def] # POP -  hij[ # PUSH index 7 - [4, 7]
After doing this, the 3rd bracket is unmatched as it pops from an empty stack, and the 4th and 7th brackets are unmatched as they were left on the stack.
Here's another way of viewing the matching:
]abc[ [ ] [ ]hij[ xyz def
Your challenge is to remove those unmatched brackets, leaving matched ones alone. For the above:
[ ]abc[ ]hij xyz def
You may use any pair of brackets out of
<>, and the input will only contain those and lowercase letters.
[abc -> abc [ ->  a[x[y]z[e]k[ -> ax[y]z[e]k ]ab[cdef]]gh[ij[klm]no]] -> ab[cdef]gh[ij[klm]no]