A parentheses string is a non-empty string consisting only of '(' and ')'. It is valid if any of the following conditions is true:
().AB (A concatenated with B), where A and B are valid parentheses strings.(A), where A is a valid parentheses string.You are given an m x n matrix of parentheses grid. A valid parentheses string path in the grid is a path satisfying all of the following conditions:
(0, 0).(m - 1, n - 1).Return true if there exists a valid parentheses string path in the grid. Otherwise, return false.
Example 1:
Input: grid = [["(","(","("],[")","(",")"],["(","(",")"],["(","(",")"]]
Output: true
Explanation: The above diagram shows two possible paths that form valid parentheses strings.
The first path shown results in the valid parentheses string "()(())".
The second path shown results in the valid parentheses string "((()))".
Note that there may be other valid parentheses string paths.
Example 2:
Input: grid = [[")",")"],["(","("]]
Output: false
Explanation: The two possible paths form the parentheses strings "))(" and ")((". Since neither of them are valid parentheses strings, we return false.
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 100grid[i][j] is either '(' or ')'.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force way to solve this is to try every single possible path through the grid. We'll check if each of these paths creates a valid string of parentheses.
Here's how the algorithm would work step-by-step:
def check_if_there_is_a_valid_parentheses_string_path(grid):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
def is_valid_parentheses_string(parentheses_string):
balance = 0
for character in parentheses_string:
if character == '(':
balance += 1
else:
balance -= 1
if balance < 0:
return False
return balance == 0
def find_path(row, column, current_string):
# If we are out of bounds, this is not a valid path
if row >= number_of_rows or column >= number_of_columns:
return False
current_string += grid[row][column]
# We have reached the destination
if row == number_of_rows - 1 and column == number_of_columns - 1:
return is_valid_parentheses_string(current_string)
# Explore going down
if find_path(row + 1, column, current_string):
return True
# Explore going right
if find_path(row, column + 1, current_string):
return True
return False
# Initiate search from top-left
return find_path(0, 0, '')The core idea is to use a technique to efficiently explore all possible paths in the grid, keeping track of the balance between open and closed parentheses. If we reach the destination with a balanced state (equal number of open and closed parentheses), it means we have found a valid path. We avoid recomputing paths by remembering previously visited locations and their parenthesis balance.
Here's how the algorithm would work step-by-step:
def check_if_there_is_a_valid_parentheses_string_path(grid):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
# Use a set to store visited states (row, col, balance).
visited = set()
def depth_first_search(row, col, parenthesis_balance):
# If out of bounds, return False
if row < 0 or row >= number_of_rows or col < 0 or col >= number_of_columns:
return False
# Update the parenthesis balance.
if grid[row][col] == '(':
parenthesis_balance += 1
else:
parenthesis_balance -= 1
# If balance is negative, it's invalid.
if parenthesis_balance < 0:
return False
# If we reached the destination.
if row == number_of_rows - 1 and col == number_of_columns - 1:
# Valid path if the parenthesis are balanced
return parenthesis_balance == 0
# Check if the state has been visited before
if (row, col, parenthesis_balance) in visited:
return False
# Mark the current state as visited.
visited.add((row, col, parenthesis_balance))
# Explore the path downwards and to the right
down = depth_first_search(row + 1, col, parenthesis_balance)
right = depth_first_search(row, col + 1, parenthesis_balance)
return down or right
# Initiate dfs with the top-left cell
return depth_first_search(0, 0, 0)| Case | How to Handle |
|---|---|
| Null or empty grid | Return false immediately, as there's no path to traverse. |
| Grid with only one cell | Return true if the single cell contains a parenthesis, otherwise false. |
| Grid with mismatched starting/ending parentheses | If the starting cell is ')' or the ending cell is '(', a valid path is impossible, so return false. |
| Long path exceeding maximum recursion depth (if using recursion) | Use dynamic programming (memoization) or iterative approach to avoid stack overflow errors. |
| Grid containing non-parenthesis characters | Treat non-parenthesis characters as invalid input and return false. |
| No valid path exists despite balanced parentheses in the grid | The algorithm should explore all possible paths and correctly return false if no valid path exists. |
| Large grid dimensions impacting memory usage | Optimize memory usage by using techniques like bitmasking to represent the parenthesis balance, or using an in-place modification approach if allowed and feasible. |
| Grid with only opening or only closing parentheses preventing balance | The path will never become balanced, leading to no valid path and return false. |