Stack · Medium

164. Check for Redundant Brackets in an Expression

Topics: Stack

Solve it on DeVert Campus - free code runner

Problem

Given a string expression containing single-letter operands, the operators + - * /, and parentheses, print 'Yes' if it contains any redundant bracket pair (one that encloses a sub-expression with no operator directly at its top level, other than a lone operand or an already-bracketed group), otherwise print 'No'.

Input and output

Input: The input is a single line containing the expression string of single-letter operands, the operators + - * /, and parentheses. Output: Print 'Yes' if the expression contains a redundant bracket pair, otherwise print 'No'.

Example

Input:
((a+b))
Output:
Yes

Constraints

1 <= |expression| <= 10^5

Key observation

The key signal for redundancy isn't the BRACKETS themselves, but the ABSENCE of an operator directly inside them - this reframing (from 'are there unnecessary brackets' to 'was an operator ever pushed in this scope') is what makes the stack-based check clean and direct.

Intuition

Check whether an expression contains any 'redundant' bracket pair - one that doesn't actually need to be there because it wraps just a single variable or an already-fully-bracketed sub-expression. Brute force: Try removing each bracket pair one at a time and check if the expression still parses/evaluates identically - this is a valid but roundabout way to detect redundancy, requiring repeated re-parsing, when a single-pass stack check directly identifies redundant pairs. Optimised: Tracking whether an OPERATOR was ever pushed between a given '(' and its matching ')' directly captures the definition of redundancy - if nothing meaningful (no operator) happened directly inside a bracket pair, wrapping it in brackets added no clarifying value, detected in a single linear pass with a stack.

Better - Stack of Characters, Pop-Until-Open

Scan the expression once, pushing every character except ')' onto a stack; when a ')' is encountered, pop characters off the stack into a temporary list until the matching '(' is popped, then scan that small popped list for the presence of an operator. If no operator was found among the popped characters, the pair is redundant, so report 'Yes'; otherwise push a placeholder representing the now-resolved group back onto the stack and continue. This handles nested brackets correctly and avoids re-scanning the whole expression per bracket, though it still does a small linear scan over each popped group. Time: O(n) amortized Space: O(n)

Optimal - Stack of 'Has Operator' Flags

Scan the expression once with a stack, but instead of pushing raw characters, push a boolean flag alongside each '(' that starts false; whenever an operator is seen, set the flag on top of the stack to true; when a ')' is seen, pop and check that top frame's flag - if it's still false, no operator ever appeared directly inside that bracket pair, so it's redundant, otherwise treat the resolved group as a single operand for its enclosing frame. Because every character triggers only constant-time work (no popping into a temporary list to rescan), this is a strict single linear pass with O(1) work per character, giving the cleanest and most efficient version of the same idea. Time: O(n) Space: O(n)

Brute Force - Match and Rescan Substrings

For every closing parenthesis, locate its matching opening parenthesis by scanning outward and tracking bracket balance, then re-scan the substring strictly between that matched pair looking for any operator (+, -, *, /) that isn't itself inside a nested, already-matched sub-bracket. If no such top-level operator is found in that substring, the bracket pair is redundant. This directly implements the definition of 'redundant' from the problem, but rescanning a substring for every single closing bracket means overlapping ranges get re-examined many times in the worst case. Time: O(n^2) Space: O(n)

Step by step

1. Use a stack: push every '(' and every OPERATOR encountered. 2. On a ')', pop elements until popping the matching '(' - if NO operator was popped in between (meaning the stack, right before hitting the '(', held only operand(s) with no operator directly inside this bracket pair), that bracket pair is redundant. 3. If at least one operator WAS popped along the way, this bracket pair is NOT redundant.

Complexity

Time: O(n) - one single pass through the expression's characters, with O(1) stack operations at each step. Space: O(n) in the worst case, for the stack.

Edge cases

A bracket wrapping a single operand like '(a)'; a bracket wrapping an already fully-bracketed sub-expression; an expression with no parentheses at all; length up to 10^5 for performance.

Interview tip

Be ready to give concrete examples of BOTH redundant cases explicitly - a bracket wrapping a single variable like '(a)', and a bracket wrapping an already-fully-bracketed group like '((a+b))' - both are flagged by the same 'no operator popped before this bracket's matching open' check.

All DSA problems