Skip to content

Commit 722fdbc

Browse files
committed
update: 有效括号系列
1 parent 5a6f3dd commit 722fdbc

File tree

3 files changed

+240
-223
lines changed

3 files changed

+240
-223
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,13 @@
187187
- [ ] [309. 最佳买卖股票时机含冷冻期](./)
188188
- [ ] [714. 买卖股票的最佳时机含手续费](./)
189189

190+
**有效括号系列**
191+
192+
- [x] [【day-38】20.有效括号](./medium/hot/38.valid-parentheses.md)
193+
- [x] [【day-38】32.最长有效括号](./medium/hot/38.longest-valid-parentheses.md)
194+
190195
**其他**
191196

192-
- [x] [有效括号系列](./medium/day-37.md)
193197
- [x] [前缀和系列](./medium/day-39.md)
194198
- [x] [581.最短无序连续子数组](./medium/day-34.md)
195199

medium/day-37.md renamed to medium/hot/38.longest-valid-parentheses.md

Lines changed: 24 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -1,218 +1,24 @@
1-
# 有效括号系列
2-
3-
**[20.有效括号](#20.有效括号)**
4-
5-
- [方法 1:栈](#方法-1:栈)
6-
- [方法 2:递归](#方法-2:递归)
7-
- [方法 3:正则](#方法-3:正则)
8-
9-
**[32.最长有效括号](#32.最长有效括号)**
10-
11-
- [方法 1:滑动窗口](#方法-1:滑动窗口)
12-
- [方法 2:动态规划](#方法-2:动态规划)
13-
- [方法 3:栈](#方法-3:栈)
14-
15-
# 20.有效括号
16-
17-
https://leetcode-cn.com/problems/valid-parentheses/
18-
19-
## 题目描述
20-
21-
```
22-
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
23-
24-
有效字符串需满足:
25-
26-
左括号必须用相同类型的右括号闭合。
27-
左括号必须以正确的顺序闭合。
28-
注意空字符串可被认为是有效字符串。
29-
30-
示例 1:
31-
32-
输入: "()"
33-
输出: true
34-
示例 2:
35-
36-
输入: "()[]{}"
37-
输出: true
38-
示例 3:
39-
40-
输入: "(]"
41-
输出: false
42-
示例 4:
43-
44-
输入: "([)]"
45-
输出: false
46-
示例 5:
47-
48-
输入: "{[]}"
49-
输出: true
50-
51-
来源:力扣(LeetCode)
52-
链接:https://leetcode-cn.com/problems/valid-parentheses
53-
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
54-
```
55-
56-
## 方法 1:栈
57-
58-
### 思路
59-
60-
- 遇到左括号就入栈。
61-
- 遇到右括号就从栈中弹出一个元素,判断两者是否是匹配的一对括号。
62-
63-
### 代码
64-
65-
JavaScript Code
66-
67-
```js
68-
/**
69-
* @param {string} s
70-
* @return {boolean}
71-
*/
72-
var isValid = function (s) {
73-
const dict = {
74-
'}': '{',
75-
')': '(',
76-
']': '[',
77-
};
78-
const stack = [];
79-
80-
for (let c of s) {
81-
if (c in dict) {
82-
if (stack.pop() !== dict[c]) {
83-
return false;
84-
}
85-
} else {
86-
stack.push(c);
87-
}
88-
}
89-
return stack.length === 0;
90-
};
91-
```
92-
93-
### 复杂度分析
94-
95-
- 时间复杂度:O(n),n 为字符串的长度。
96-
- 空间复杂度:O(n),n 为字符串的长度。
97-
98-
## 方法 2:递归
99-
100-
### 思路
101-
102-
还记得[产品经理法](https://github.com/leetcode-pp/91alg-1/issues/32#issuecomment-643620727)么?假设我们现在已经有了一个 `isValid` 方法,可以验证一个字符串 s 是否由有效括号组成。
103-
104-
**那么子问题是什么?**
105-
106-
如果 s 的第一个字符是左括号的话,那我们应该可以找到它对应右括号的下标 index,如果找不到说明就不是有效括号啦。
107-
108-
如果找到了,那么现在问题就变成了:
109-
110-
- (0, index) 中间这段字符串是否包含有效括号?
111-
- (index, s.length) 这段字符串是否包含有效括号?
112-
113-
> 开括号表示不包括边界
114-
115-
**大问题和小问题的关系是什么?**
116-
117-
显然必须两个小问题的结果都是 true 才行啦,也就是:
118-
119-
`isValid(s) = isValid(1, index - 1) && isValid(index + 1, s.length)`
120-
121-
**递归出口在哪里?**
122-
123-
- 如果字符串第一个字符不是左括号,`return false`
124-
- 如果字符串为空,`return true`
125-
- 还有一个,如果字符串长度是奇数的话,我们也可以提前 `return false`
126-
127-
**关于如何找到对应的右括号下标**
128-
129-
用一个 `counter` 来记录当前遇到的括号,比如,我们要找的是 '(' 的对应右括号 ')',那么在遍历字符串时:
130-
131-
- 遇到 '(' 时 `counter++`
132-
- 遇到 ')' 时 `counter--`
133-
-`counter === 0` 时说明我们找到了
134-
- 如果遍历结束后 `counter > 0` 说明找不到匹配的右括号
135-
136-
### 代码
137-
138-
JavaScript Code
139-
140-
```js
141-
const dict = {
142-
'(': ')',
143-
'{': '}',
144-
'[': ']',
145-
};
146-
147-
const matchClose = (s, start, end, open, close) => {
148-
let count = 0;
149-
for (let i = start; i <= end; i++) {
150-
if (s[i] === open) count++;
151-
if (s[i] === close) count--;
152-
if (count === 0) return i;
153-
}
154-
return -1;
155-
};
156-
157-
/**
158-
* @param {string} s
159-
* @return {boolean}
160-
*/
161-
const isValid = function (s) {
162-
if (!s) return true;
163-
if (s.length % 2 === 1) return false;
164-
if (!(s[0] in dict)) return false;
165-
166-
const closeIndex = matchClose(s, 0, s.length - 1, s[0], dict[s[0]]);
167-
if (closeIndex === -1) return false;
168-
return (
169-
isValid(s.slice(1, closeIndex)) &&
170-
isValid(s.slice(closeIndex + 1, s.length))
171-
);
172-
};
173-
```
174-
175-
### 复杂度分析
176-
177-
- 时间复杂度:O(n _ 2(n/2),递归的时间复杂度是 O(2^(n/2)),n 为字符串的长度,树的最大深度应该是 n/2 吧。每次递归中 `matchClose` 寻找匹配的闭合括号的时间复杂度大概是 O(n) 吧,所以时间复杂度是 O(n _ 2(n/2) ??? 我凌乱了
178-
- 空间复杂度:O(n),n 为字符串的长度,调用栈的最大深度是 n/2。
179-
180-
## 方法 3:正则
181-
182-
### 思路
183-
184-
不断地把 `()` `{}` `[]` 替换成空字符,直到:
185-
186-
- s 变成了空字符,那么结果就是 `true`,或者,
187-
- s 长度不为空,但是 s 中已经没有 `()``{}` 或者 `[]` 括号对了,那么结果就是 `false`
188-
189-
### 代码
190-
191-
JavaScript Code
192-
193-
```js
194-
/**
195-
* @param {string} s
196-
* @return {boolean}
197-
*/
198-
const isValid = function (s) {
199-
const reg = /\[\]|\(\)|\{\}/;
200-
while (reg.test(s)) {
201-
s = s.replace(reg, '');
202-
}
203-
return s.length === 0;
204-
};
205-
```
206-
207-
### 复杂度分析
208-
209-
- 时间复杂度:O(n),n 为字符串的长度。最坏的情况下,每次循环只能替换一对括号,比如 "(((((())))))",需要循环 n/2 次。
210-
- 空间复杂度:O(1)。
211-
2121
# 32.最长有效括号
2132

2143
https://leetcode-cn.com/problems/longest-valid-parentheses/
2154

5+
- [32.最长有效括号](#32最长有效括号)
6+
- [题目描述](#题目描述)
7+
- [方法 1:滑动窗口](#方法-1滑动窗口)
8+
- [思路](#思路)
9+
- [图解](#图解)
10+
- [代码](#代码)
11+
- [复杂度分析](#复杂度分析)
12+
- [方法 2:动态规划](#方法-2动态规划)
13+
- [思路](#思路-1)
14+
- [图解](#图解-1)
15+
- [代码](#代码-1)
16+
- [复杂度分析](#复杂度分析-1)
17+
- [方法 3:栈](#方法-3栈)
18+
- [思路](#思路-2)
19+
- [代码](#代码-2)
20+
- [复杂度分析](#复杂度分析-2)
21+
21622
## 题目描述
21723

21824
```
@@ -302,8 +108,8 @@ var longestValidParentheses = function (s) {
302108

303109
### 复杂度分析
304110

305-
- 时间复杂度:O(n),n 为字符串的长度。
306-
- 空间复杂度:O(n),n 为字符串的长度。
111+
- 时间复杂度:$O(n)$,n 为字符串的长度。
112+
- 空间复杂度:$O(n)$,n 为字符串的长度。
307113

308114
## 方法 2:动态规划
309115

@@ -363,16 +169,16 @@ var longestValidParentheses = function (s) {
363169

364170
### 复杂度分析
365171

366-
- 时间复杂度:O(n),n 为字符串的长度。
367-
- 空间复杂度:O(n),n 为字符串的长度。
172+
- 时间复杂度:$O(n)$,n 为字符串的长度。
173+
- 空间复杂度:$O(n)$,n 为字符串的长度。
368174

369175
## 方法 3:栈
370176

371177
### 思路
372178

373179
用一个栈来检查括号的有效性,用一个数组 `valid` 来记录匹配括号对的位置。
374180

375-
- 栈的用法跟[20.有效括号](#方法-1:栈)里的一样,不过入栈的不是 `(`,而是它们的下标。
181+
- 栈的用法跟[20.有效括号](./38.valid-parentheses.md)里的一样,不过入栈的不是 `(`,而是它们的下标。
376182
- 在遍历过程中,如果碰到 `)`,就从栈中弹出一个元素,这个元素就是 `)` 对应的 `(` 的下标。
377183
- 接着我们在 `valid` 中这两个下标对应的位置做个标识 `1`,说明这里找到了一对有效括号。
378184
- 等遍历结束之后,在 `valid` 中找到连续最长的 `1` 序列。
@@ -414,9 +220,5 @@ var longestValidParentheses = function (s) {
414220

415221
### 复杂度分析
416222

417-
- 时间复杂度:O(n),n 为字符串的长度。
418-
- 空间复杂度:O(n),n 为字符串的长度。
419-
420-
## 官方题解
421-
422-
https://github.com/azl397985856/leetcode/blob/master/problems/32.longest-valid-parentheses.md
223+
- 时间复杂度:$O(n)$,n 为字符串的长度。
224+
- 空间复杂度:$O(n)$,n 为字符串的长度。

0 commit comments

Comments
 (0)