↓Skip to main content
  1. LeetCode/

LeetCode 2267: Check if There Is a Valid Parentheses String Path

·3 mins· ·
LeetCode Hard Dynamic-Programming Grid-Dp Matrix Bracket-Sequences
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-10-13

  • Submissions: Wrong Answer ×2 → Accepted

Approach
#

Whether a bracket string is valid depends only on the current balance (opens minus closes): never negative along the way, 0 at the end. So the state is (r, c, bal).

Pruning:

  • An odd path length m + n - 1, a ) at the start, or a ( at the end: impossible.
  • bal < 0: already invalid.
  • bal > remaining steps: even all ) from here could not close it.

BFS right / down from (0, 0, 1) with a seen set for repeated states, returning True at the end with bal == 0.

My Attempts
#

The first two versions simulated brackets with a stack, but every path shared the same list: queue.append((nr, nc, stack)) enqueued the same object, so one path’s pushes and pops affected the others.

VersionProblem
Attempt 1The stack already held grid[0][0] at the start, and processing the start pushed it again, counting the first ( twice. For [["(", ")"]] the answer is True; it returned False
Attempt 2Fixed the start, but the stack was still shared. For [["(", ")"], ["(", ")"]] the path length is 3, so nothing is valid and the answer is False; it returned True
ACUsed an integer bal as the state, with pruning and seen

Solution
#

from collections import deque

class Solution:
    def hasValidPath(self, grid: List[List[str]]) -> bool:
        m, n = len(grid), len(grid[0])
        if (m + n - 1) % 2 or grid[0][0] == ")" or grid[-1][-1] == "(":
            return False

        start = (0, 0, 1)
        seen = {start}
        queue = deque([start])
        while queue:
            r, c, bal = queue.popleft()
            if r == m - 1 and c == n - 1 and bal == 0:
                return True
            for nr, nc in ((r + 1, c), (r, c + 1)):
                if nr < m and nc < n:
                    nb = bal + (1 if grid[nr][nc] == "(" else -1)
                    remaining = (m - 1 - nr) + (n - 1 - nc)
                    if 0 <= nb <= remaining and (nr, nc, nb) not in seen:
                        seen.add((nr, nc, nb))
                        queue.append((nr, nc, nb))
        return False

Complexity
#

Time O(mn(m + n)) (the balance is at most the path length), and the same for space.

Mistakes to Avoid
#

  • Putting a mutable list into the queue: every path shares one object.
  • Do not count the starting bracket twice.
  • Without the bal > remaining prune, many impossible states get searched.

Interview Explanation
#

Validity depends only on the balance, so the state is the position plus the balance. I BFS right / down from the start, rejecting negative balances and balances above the remaining steps, using seen to drop repeats, and succeed when the end is reached with balance exactly 0. Odd path lengths, a starting ) and an ending ( are ruled out first. Time O(mn(m + n)).

Related

LeetCode 2328: Number of Increasing Paths in a Grid
·2 mins
LeetCode Hard Dynamic-Programming Grid-Dp Memoization Topological-Sort Matrix
LeetCode 2328 note: strictly increasing means no cycles; dp[cell] = 1 + Σ dp[larger neighbors], processed from largest to smallest value (or by memoized DFS), summed over all cells
LeetCode 3651: Minimum Cost Path with Teleportations
·2 mins
LeetCode Hard Dynamic-Programming Grid-Dp Matrix Array
LeetCode 3651 note: compute layer by layer over teleports; arriving at a cell by teleport costs the previous layer’s minimum over cells with value >= it, found with a running minimum after sorting, followed by the usual right / down grid DP
LeetCode 773: Sliding Puzzle
·2 mins
LeetCode Hard Breadth-First-Search Dynamic-Programming Memoization Matrix
LeetCode 773 note: there are only 6! = 720 boards, so flatten each board into a string as a BFS state, with swaps of 0 and a neighbor as the moves
LeetCode 3989: Maximum Consistent Columns in a Grid
·2 mins
LeetCode Hard Dynamic-Programming Matrix Array
LeetCode 3989 note: the kept columns form a subsequence constrained only between neighbors; an LIS-style DP with dp[j] = the longest valid sequence ending at column j
LeetCode 1289: Minimum Falling Path Sum II
·3 mins
LeetCode Hard Dynamic-Programming Grid-Dp
LeetCode note for Minimum Falling Path Sum II, rebuilt from the original learning note
LeetCode 174: Dungeon Game
·3 mins
LeetCode Hard Dynamic-Programming Grid-Dp
LeetCode note for Dungeon Game, rebuilt from the original learning note