Check the grid if there is a path (from (0, 0) to (n, m)) that can form a valid paratheses combination. We can only choose to go down or right.
Finding a path is not difficult, but the judgment of a valid path is not easy to think.
Usually, we use stack to check whether the parentheses are valid or not, we found that when closing parentheses at the bottom of the stack, the combination must be invalid. Moreover, another invalid condition is if the number of opening parentheses and closing parentheses are different, then it must be invalid.
We can try to use 1 and -1 to represent opening parentheses and closing parentheses. We will add all of these values to get a hint that whether it is a valid path and call this sum Balance. So, if the path does not break these two conditions that means it has the chance to be a valid path.
Obviously, it is quite easy to TLE, we have to add memorization in this program to avoid repeating the path.
This is quite tricky because every path would have a different number of parentheses, but what we know is if two paths have the same Balance, it must be the positive Balance or 0, as the negative case is invalid and we already blocked it. from this, we know if the Balance is the same then the pattern of the combination would also be the same.
So, the total number of the Balance state is 200, as the worst case is all the parentheses are opening parentheses.
The visited or DP array would be 3 dimension array. DP[i][j][balance] = have we been here before carrying the same balance.
The maximum size of the grid is 100 * 100. That means the path length would be 200.
int dp[100][100][201] = {};
bool dfs(vector<vector<char>>& grid, int i, int j, int bal) {
int m = grid.size(), n = grid[0].size();
bal += grid[i][j] == '(' ? 1 : -1;
//balance is negative, means ) is at the bottom of the stack
if (bal < 0)
return false;
//if the destination has 0 balance, which means there is a valid path
if (i == m - 1 && j == n - 1 && bal == 0)
return true;
//if we have been to (i, j) and carry the same balance, we dont need to search again
//why we have arrived need to return false?
//because if we have arrived and the program are still runing means this is invalid path
if (dp[i][j][bal])
return false;
// to ensure the search is inside the boundary
if (i < m - 1)
if (dfs(grid, i + 1, j, bal))
return true;
if (j < n - 1)
if (dfs(grid, i, j + 1, bal))
return true;
// mark the point that we have arrived and the balance that we carried on
dp[i][j][bal] = true;
return false;
}
bool hasValidPath(vector<vector<char>>& grid) {
return dfs(grid, 0, 0, 0);
}