Skip to content

Commit 9210400

Browse files
committed
added solution to 2267
1 parent 36a1f41 commit 9210400

File tree

1 file changed

+278
-0
lines changed

1 file changed

+278
-0
lines changed
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
---
2+
id: check-if-there-is-a-valid-parenthesis-string-path
3+
title: Check If there is a Valid Parenthesis String Path
4+
sidebar_label: 2267-Check If there is a Valid Parenthesis String Path
5+
tags:
6+
- Valid Parentheses Path
7+
- Brute Force
8+
- Optimized
9+
- LeetCode
10+
- Java
11+
- Python
12+
- C++
13+
description: "This is a solution to the Valid Parentheses Path problem on LeetCode."
14+
sidebar_position: 2
15+
---
16+
17+
In this tutorial, we will solve the Valid Parentheses Path problem using two different approaches: brute force and optimized. We will provide the implementation of the solution in C++, Java, and Python.
18+
19+
## Problem Description
20+
21+
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:
22+
23+
- The path starts from the upper left cell (0, 0).
24+
- The path ends at the bottom-right cell (m - 1, n - 1).
25+
- The path only ever moves down or right.
26+
- The resulting parentheses string formed by the path is valid.
27+
28+
Return true if there exists a valid parentheses string path in the grid. Otherwise, return false.
29+
30+
### Examples
31+
32+
**Example 1:**
33+
34+
```
35+
Input: grid = [["(","(","("],[")","(",")"],["(","(",")"],["(","(",")"]]
36+
Output: true
37+
Explanation: The above diagram shows two possible paths that form valid parentheses strings.
38+
The first path shown results in the valid parentheses string "()(())".
39+
The second path shown results in the valid parentheses string "((()))".
40+
Note that there may be other valid parentheses string paths.
41+
```
42+
43+
**Example 2:**
44+
45+
```
46+
Input: grid = [[")",")"],["(","("]]
47+
Output: false
48+
Explanation: The two possible paths form the parentheses strings "))(" and ")((". Since neither of them are valid parentheses strings, we return false.
49+
50+
```
51+
52+
### Constraints
53+
54+
- `m == grid.length`
55+
- `n == grid[i].length`
56+
- `1 <= m, n <= 100`
57+
- `grid[i][j]` is either '(' or ')'.
58+
59+
---
60+
61+
## Solution for Valid Parentheses Path Problem
62+
63+
### Intuition and Approach
64+
65+
The problem can be solved using a brute force approach or an optimized approach. The brute force approach directly explores all possible paths, while the optimized approach uses dynamic programming to efficiently check valid paths.
66+
67+
<Tabs>
68+
<tabItem value="Brute Force" label="Brute Force">
69+
70+
### Approach 1: Brute Force (Naive)
71+
72+
The brute force approach recursively explores all possible paths from the top-left to the bottom-right cell, ensuring the parentheses string remains valid.
73+
74+
#### Code in Different Languages
75+
76+
<Tabs>
77+
<TabItem value="C++" label="C++" default>
78+
<SolutionAuthor name="@ImmidiSivani"/>
79+
80+
```cpp
81+
class Solution {
82+
public:
83+
bool isValidPath(vector<vector<char>>& grid, int i, int j, int balance) {
84+
if (i >= grid.size() || j >= grid[0].size() || balance < 0) return false;
85+
balance += (grid[i][j] == '(') ? 1 : -1;
86+
if (i == grid.size() - 1 && j == grid[0].size() - 1) return balance == 0;
87+
return isValidPath(grid, i + 1, j, balance) || isValidPath(grid, i, j + 1, balance);
88+
}
89+
90+
bool hasValidPath(vector<vector<char>>& grid) {
91+
return isValidPath(grid, 0, 0, 0);
92+
}
93+
};
94+
```
95+
96+
</TabItem>
97+
<TabItem value="Java" label="Java">
98+
<SolutionAuthor name="@ImmidiSivani"/>
99+
100+
```java
101+
class Solution {
102+
public boolean isValidPath(char[][] grid, int i, int j, int balance) {
103+
if (i >= grid.length || j >= grid[0].length || balance < 0) return false;
104+
balance += (grid[i][j] == '(') ? 1 : -1;
105+
if (i == grid.length - 1 && j == grid[0].length - 1) return balance == 0;
106+
return isValidPath(grid, i + 1, j, balance) || isValidPath(grid, i, j + 1, balance);
107+
}
108+
109+
public boolean hasValidPath(char[][] grid) {
110+
return isValidPath(grid, 0, 0, 0);
111+
}
112+
}
113+
```
114+
115+
</TabItem>
116+
<TabItem value="Python" label="Python">
117+
<SolutionAuthor name="@ImmidiSivani"/>
118+
119+
```python
120+
class Solution:
121+
def isValidPath(self, grid: List[List[str]], i: int, j: int, balance: int) -> bool:
122+
if i >= len(grid) or j >= len(grid[0]) or balance < 0:
123+
return False
124+
balance += 1 if grid[i][j] == '(' else -1
125+
if i == len(grid) - 1 and j == len(grid[0]) - 1:
126+
return balance == 0
127+
return self.isValidPath(grid, i + 1, j, balance) or self.isValidPath(grid, i, j + 1, balance)
128+
129+
def hasValidPath(self, grid: List[List[str]]) -> bool:
130+
return self.isValidPath(grid, 0, 0, 0)
131+
```
132+
133+
</TabItem>
134+
</Tabs>
135+
136+
#### Complexity Analysis
137+
138+
- Time Complexity: Exponential due to exploring all paths.
139+
- Space Complexity: Exponential due to recursive call stack.
140+
- The brute force approach is inefficient for larger grids.
141+
142+
</tabItem>
143+
<tabItem value="Optimized" label="Optimized">
144+
145+
### Approach 2: Optimized Approach
146+
147+
The optimized approach uses dynamic programming to track valid paths with different balances at each cell. This significantly reduces redundant calculations.
148+
149+
#### Code in Different Languages
150+
151+
<Tabs>
152+
<TabItem value="C++" label="C++" default>
153+
<SolutionAuthor name="@ImmidiSivani"/>
154+
155+
```cpp
156+
class Solution {
157+
public:
158+
bool hasValidPath(vector<vector<char>>& grid) {
159+
int m = grid.size(), n = grid[0].size();
160+
if (grid[0][0] == ')') return false;
161+
vector<vector<vector<bool>>> dp(m, vector<vector<bool>>(n, vector<bool>(m + n, false)));
162+
dp[0][0][1] = true;
163+
164+
for (int i = 0; i < m; ++i) {
165+
for (int j = 0; j < n; ++j) {
166+
for (int k = 0; k <= m + n; ++k) {
167+
if (dp[i][j][k]) {
168+
if (i + 1 < m) {
169+
int new_balance = k + (grid[i + 1][j] == '(' ? 1 : -1);
170+
if (new_balance >= 0 && new_balance <= m + n) {
171+
dp[i + 1][j][new_balance] = true;
172+
}
173+
}
174+
if (j + 1 < n) {
175+
int new_balance = k + (grid[i][j + 1] == '(' ? 1 : -1);
176+
if (new_balance >= 0 && new_balance <= m + n) {
177+
dp[i][j + 1][new_balance] = true;
178+
}
179+
}
180+
}
181+
}
182+
}
183+
}
184+
185+
return dp[m - 1][n - 1][0];
186+
}
187+
};
188+
```
189+
190+
</TabItem>
191+
<TabItem value="Java" label="Java">
192+
<SolutionAuthor name="@ImmidiSivani"/>
193+
194+
```java
195+
class Solution {
196+
public boolean hasValidPath(char[][] grid) {
197+
int m = grid.length, n = grid[0].length;
198+
if (grid[0][0] == ')') return false;
199+
boolean[][][] dp = new boolean[m][n][m + n];
200+
dp[0][0][1] = true;
201+
202+
for (int i = 0; i < m; ++i) {
203+
for (int j = 0; j < n; ++j) {
204+
for (int k = 0; k <= m + n; ++k) {
205+
if (dp[i][j][k]) {
206+
if (i + 1 < m) {
207+
int new_balance = k + (grid[i + 1][j] == '(' ? 1 : -1);
208+
if (new_balance >= 0 && new_balance <= m + n) {
209+
dp[i + 1][j][new_balance] = true;
210+
}
211+
}
212+
if (j + 1 < n) {
213+
int new_balance = k + (grid[i][j + 1] == '(' ? 1 : -1);
214+
if (new_balance >= 0 && new_balance <= m + n) {
215+
dp[i][j + 1][new_balance] = true;
216+
}
217+
}
218+
}
219+
}
220+
}
221+
}
222+
223+
return dp[m - 1][n - 1][0];
224+
}
225+
}
226+
```
227+
228+
</TabItem>
229+
<TabItem value="Python" label="Python">
230+
<SolutionAuthor name="@ImmidiSivani"/>
231+
232+
```python
233+
class Solution:
234+
def hasValidPath(self, grid: List[List[str]]) -> bool:
235+
m, n = len(grid), len(grid[0])
236+
if grid[0][0] == ')':
237+
return False
238+
dp = [[[False] * (m + n) for _ in range(n)] for _ in range(m)]
239+
dp[0][0][1] = True
240+
241+
for i in range(m):
242+
for j in range(n):
243+
for k in range(m + n):
244+
if dp[i][j][k]:
245+
if i + 1 < m:
246+
new_balance = k + (1 if grid[i + 1][j] == '(' else -1)
247+
if 0 <= new_balance <= m + n:
248+
dp[i + 1][j][new_balance] = True
249+
if j + 1 < n:
250+
new_balance = k + (1 if grid[i][j + 1] == '(' else -1)
251+
if 0 <= new_balance <= m + n:
252+
dp[i][j + 1][new_balance] = True
253+
254+
return dp[m - 1][n - 1][0]
255+
```
256+
257+
</TabItem>
258+
</Tabs>
259+
260+
#### Complexity Analysis
261+
262+
- Time Complexity: $O( (m + n))$
263+
- Space Complexity: $O( (m + n))$
264+
- Where `m` is the number of rows and `n` is the number of columns.
265+
- The optimized approach efficiently tracks valid paths using dynamic programming.
266+
267+
</tabItem>
268+
</Tabs>
269+
270+
---
271+
272+
<h2>Authors:</h2>
273+
274+
<div style={{display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: '10px'}}>
275+
{['ImmidiSivani'].map(username => (
276+
<Author key={username} username={username} />
277+
))}
278+
</div>

0 commit comments

Comments
 (0)