Skip to content

Commit c58c5de

Browse files
committed
feat: add solutions to lc problem: No.0678
No.0678.Valid Parenthesis String
1 parent 4991fee commit c58c5de

File tree

4 files changed

+209
-9
lines changed

4 files changed

+209
-9
lines changed

README_EN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ You can also contribute to [doocs/leetcode](https://github.com/doocs/leetcode) u
196196

197197
<a href="https://github.com/doocs/leetcode/stargazers" target="_blank"><img src="./images/starcharts.svg" alt="Stargazers over time" /></a>
198198

199-
## Contributors
199+
## Our Top Contributors
200200

201201
This project exists thanks to all the people who contribute.
202202

solution/0600-0699/0678.Valid Parenthesis String/README.md

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,24 @@
4747

4848
<!-- 这里可写通用的实现逻辑 -->
4949

50-
两遍扫描,第一遍从左往右,确定每一个右括号都可以成功配对,第二遍从右往左,确定每一个左括号都可以成功配对
50+
**方法一:动态规划**
51+
52+
定义 $dp[i][j]$ 表示字符串 $s$ 中下标范围 $[i..j]$ 内的子串是否为有效括号字符串。答案为 $dp[0][n - 1]$。
53+
54+
子串长度为 $1$ 时,如果字符 $s[i]$ 为 `*`,则 $dp[i][i]$ 为 `true`,否则为 `false`
55+
56+
子串长度大于 $1$ 时,如果满足下面任意一种情况,则 $dp[i][j]$ 为 `true`
57+
58+
- 子串 $s[i..j]$ 的左边界为 `(``*`,且右边界为 `*``)`,且 $s[i+1..j-1]$ 为有效括号字符串;
59+
- 子串 $s[i..j]$ 中的任意下标 $k$,如果 $s[i..k]$ 为有效括号字符串,且 $s[k+1..j]$ 为有效括号字符串,则 $s[i..j]$ 为有效括号字符串。
60+
61+
时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 `s` 的长度。
62+
63+
**方法二:贪心 + 两遍扫描**
64+
65+
两遍扫描,第一遍从左往右,确定每一个右括号都可以成功配对,第二遍从右往左,确定每一个左括号都可以成功配对。
66+
67+
时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为字符串 `s` 的长度。
5168

5269
<!-- tabs:start -->
5370

@@ -59,7 +76,25 @@
5976
class Solution:
6077
def checkValidString(self, s: str) -> bool:
6178
n = len(s)
62-
left, asterisk = 0, 0
79+
dp = [[False] * n for _ in range(n)]
80+
for i, c in enumerate(s):
81+
dp[i][i] = c == '*'
82+
for i in range(n - 2, -1, -1):
83+
for j in range(i + 1, n):
84+
dp[i][j] = (
85+
s[i] in '(*' and s[j] in '*)' and (i + 1 == j or dp[i + 1][j - 1])
86+
)
87+
dp[i][j] = dp[i][j] or any(
88+
dp[i][k] and dp[k + 1][j] for k in range(i, j)
89+
)
90+
return dp[0][-1]
91+
```
92+
93+
```python
94+
class Solution:
95+
def checkValidString(self, s: str) -> bool:
96+
n = len(s)
97+
left = asterisk = 0
6398
for i in range(n):
6499
if s[i] == "(":
65100
left += 1
@@ -72,7 +107,7 @@ class Solution:
72107
return False
73108
else:
74109
asterisk += 1
75-
right, asterisk = 0, 0
110+
right = asterisk = 0
76111
for i in range(n - 1, -1, -1):
77112
if s[i] == ")":
78113
right += 1
@@ -92,6 +127,28 @@ class Solution:
92127

93128
<!-- 这里可写当前语言的特殊实现逻辑 -->
94129

130+
```java
131+
class Solution {
132+
public boolean checkValidString(String s) {
133+
int n = s.length();
134+
boolean[][] dp = new boolean[n][n];
135+
for (int i = 0; i < n; ++i) {
136+
dp[i][i] = s.charAt(i) == '*';
137+
}
138+
for (int i = n - 2; i >= 0; --i) {
139+
for (int j = i + 1; j < n; ++j) {
140+
char a = s.charAt(i), b = s.charAt(j);
141+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i + 1 == j || dp[i + 1][j - 1]);
142+
for (int k = i; k < j && !dp[i][j]; ++k) {
143+
dp[i][j] = dp[i][k] && dp[k + 1][j];
144+
}
145+
}
146+
}
147+
return dp[0][n - 1];
148+
}
149+
}
150+
```
151+
95152
```java
96153
class Solution {
97154
public boolean checkValidString(String s) {
@@ -137,6 +194,29 @@ class Solution {
137194

138195
### **C++**
139196

197+
```cpp
198+
class Solution {
199+
public:
200+
bool checkValidString(string s) {
201+
int n = s.size();
202+
vector<vector<bool>> dp(n, vector<bool>(n));
203+
for (int i = 0; i < n; ++i) {
204+
dp[i][i] = s[i] == '*';
205+
}
206+
for (int i = n - 2; i >= 0; --i) {
207+
for (int j = i + 1; j < n; ++j) {
208+
char a = s[i], b = s[j];
209+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i + 1 == j || dp[i + 1][j - 1]);
210+
for (int k = i; k < j && !dp[i][j]; ++k) {
211+
dp[i][j] = dp[i][k] && dp[k + 1][j];
212+
}
213+
}
214+
}
215+
return dp[0][n - 1];
216+
}
217+
};
218+
```
219+
140220
```cpp
141221
class Solution {
142222
public:
@@ -180,6 +260,27 @@ public:
180260

181261
### **Go**
182262

263+
```go
264+
func checkValidString(s string) bool {
265+
n := len(s)
266+
dp := make([][]bool, n)
267+
for i := range dp {
268+
dp[i] = make([]bool, n)
269+
dp[i][i] = s[i] == '*'
270+
}
271+
for i := n - 2; i >= 0; i-- {
272+
for j := i + 1; j < n; j++ {
273+
a, b := s[i], s[j]
274+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i+1 == j || dp[i+1][j-1])
275+
for k := i; k < j && !dp[i][j]; k++ {
276+
dp[i][j] = dp[i][k] && dp[k+1][j]
277+
}
278+
}
279+
}
280+
return dp[0][n-1]
281+
}
282+
```
283+
183284
```go
184285
func checkValidString(s string) bool {
185286
n := len(s)

solution/0600-0699/0678.Valid Parenthesis String/README_EN.md

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,22 @@
3636

3737
## Solutions
3838

39-
Scan twice, first from left to right to make sure that each of the closing brackets is matched successfully, and second from right to left to make sure that each of the opening brackets is matched successfully
39+
**Approach 1: Dynamic Programming**
40+
41+
Let `dp[i][j]` be true if and only if the interval `s[i], s[i+1], ..., s[j]` can be made valid. Then `dp[i][j]` is true only if:
42+
43+
- `s[i]` is `'*'`, and the interval `s[i+1], s[i+2], ..., s[j]` can be made valid;
44+
- or, `s[i]` can be made to be `'('`, and there is some `k` in `[i+1, j]` such that `s[k]` can be made to be `')'`, plus the two intervals cut by `s[k]` (`s[i+1: k] and s[k+1: j+1]`) can be made valid;
45+
46+
- Time Complexity: $O(n^3)$, where $n$ is the length of the string. There are $O(n^2)$ states corresponding to entries of dp, and we do an average of $O(n)$ work on each state.
47+
- Space Complexity: $O(n^2)$.
48+
49+
**Approach 2: Greedy**
50+
51+
Scan twice, first from left to right to make sure that each of the closing brackets is matched successfully, and second from right to left to make sure that each of the opening brackets is matched successfully.
52+
53+
- Time Complexity: $O(n)$, where $n$ is the length of the string.
54+
- Space Complexity: $O(1)$.
4055

4156
<!-- tabs:start -->
4257

@@ -46,7 +61,25 @@ Scan twice, first from left to right to make sure that each of the closing brack
4661
class Solution:
4762
def checkValidString(self, s: str) -> bool:
4863
n = len(s)
49-
left, asterisk = 0, 0
64+
dp = [[False] * n for _ in range(n)]
65+
for i, c in enumerate(s):
66+
dp[i][i] = c == '*'
67+
for i in range(n - 2, -1, -1):
68+
for j in range(i + 1, n):
69+
dp[i][j] = (
70+
s[i] in '(*' and s[j] in '*)' and (i + 1 == j or dp[i + 1][j - 1])
71+
)
72+
dp[i][j] = dp[i][j] or any(
73+
dp[i][k] and dp[k + 1][j] for k in range(i, j)
74+
)
75+
return dp[0][-1]
76+
```
77+
78+
```python
79+
class Solution:
80+
def checkValidString(self, s: str) -> bool:
81+
n = len(s)
82+
left = asterisk = 0
5083
for i in range(n):
5184
if s[i] == "(":
5285
left += 1
@@ -59,7 +92,7 @@ class Solution:
5992
return False
6093
else:
6194
asterisk += 1
62-
right, asterisk = 0, 0
95+
right = asterisk = 0
6396
for i in range(n - 1, -1, -1):
6497
if s[i] == ")":
6598
right += 1
@@ -77,6 +110,28 @@ class Solution:
77110

78111
### **Java**
79112

113+
```java
114+
class Solution {
115+
public boolean checkValidString(String s) {
116+
int n = s.length();
117+
boolean[][] dp = new boolean[n][n];
118+
for (int i = 0; i < n; ++i) {
119+
dp[i][i] = s.charAt(i) == '*';
120+
}
121+
for (int i = n - 2; i >= 0; --i) {
122+
for (int j = i + 1; j < n; ++j) {
123+
char a = s.charAt(i), b = s.charAt(j);
124+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i + 1 == j || dp[i + 1][j - 1]);
125+
for (int k = i; k < j && !dp[i][j]; ++k) {
126+
dp[i][j] = dp[i][k] && dp[k + 1][j];
127+
}
128+
}
129+
}
130+
return dp[0][n - 1];
131+
}
132+
}
133+
```
134+
80135
```java
81136
class Solution {
82137
public boolean checkValidString(String s) {
@@ -122,6 +177,29 @@ class Solution {
122177

123178
### **C++**
124179

180+
```cpp
181+
class Solution {
182+
public:
183+
bool checkValidString(string s) {
184+
int n = s.size();
185+
vector<vector<bool>> dp(n, vector<bool>(n));
186+
for (int i = 0; i < n; ++i) {
187+
dp[i][i] = s[i] == '*';
188+
}
189+
for (int i = n - 2; i >= 0; --i) {
190+
for (int j = i + 1; j < n; ++j) {
191+
char a = s[i], b = s[j];
192+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i + 1 == j || dp[i + 1][j - 1]);
193+
for (int k = i; k < j && !dp[i][j]; ++k) {
194+
dp[i][j] = dp[i][k] && dp[k + 1][j];
195+
}
196+
}
197+
}
198+
return dp[0][n - 1];
199+
}
200+
};
201+
```
202+
125203
```cpp
126204
class Solution {
127205
public:
@@ -165,6 +243,27 @@ public:
165243

166244
### **Go**
167245

246+
```go
247+
func checkValidString(s string) bool {
248+
n := len(s)
249+
dp := make([][]bool, n)
250+
for i := range dp {
251+
dp[i] = make([]bool, n)
252+
dp[i][i] = s[i] == '*'
253+
}
254+
for i := n - 2; i >= 0; i-- {
255+
for j := i + 1; j < n; j++ {
256+
a, b := s[i], s[j]
257+
dp[i][j] = (a == '(' || a == '*') && (b == '*' || b == ')') && (i+1 == j || dp[i+1][j-1])
258+
for k := i; k < j && !dp[i][j]; k++ {
259+
dp[i][j] = dp[i][k] && dp[k+1][j]
260+
}
261+
}
262+
}
263+
return dp[0][n-1]
264+
}
265+
```
266+
168267
```go
169268
func checkValidString(s string) bool {
170269
n := len(s)

solution/0600-0699/0678.Valid Parenthesis String/Solution.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Solution:
22
def checkValidString(self, s: str) -> bool:
33
n = len(s)
4-
left, asterisk = 0, 0
4+
left = asterisk = 0
55
for i in range(n):
66
if s[i] == "(":
77
left += 1
@@ -14,7 +14,7 @@ def checkValidString(self, s: str) -> bool:
1414
return False
1515
else:
1616
asterisk += 1
17-
right, asterisk = 0, 0
17+
right = asterisk = 0
1818
for i in range(n - 1, -1, -1):
1919
if s[i] == ")":
2020
right += 1

0 commit comments

Comments
 (0)