678. 有效的括号字符串
题目描述
给你一个只包含三种字符的字符串,支持的字符类型分别是 '('、')' 和 '*'。请你检验这个字符串是否为有效字符串,如果是 有效 字符串返回 true 。
有效 字符串符合如下规则:
- 任何左括号
'('必须有相应的右括号')'。 - 任何右括号
')'必须有相应的左括号'('。 - 左括号
'('必须在对应的右括号之前')'。 '*'可以被视为单个右括号')',或单个左括号'(',或一个空字符串""。
示例 1:
输入:s = "()" 输出:true
示例 2:
输入:s = "(*)" 输出:true
示例 3:
输入:s = "(*))" 输出:true
提示:
1 <= s.length <= 100s[i]为'('、')'或'*'
解法
方法一:动态规划
思考
* 可当左、右或空,判断整串是否合法。回溯三种选择在长度 \(100\) 时偏慢。
区间 DP:\(dp[i][j]\) 表示 \(s[i..j]\) 是否合法。长度为 \(1\) 仅 * 为真;更长则「两端能配对且内部合法」或在某处拆成两段合法串。
定义 \(dp[i][j]\) 表示字符串 \(s\) 中下标范围 \([i..j]\) 内的子串是否为有效括号字符串。答案为 \(dp[0][n - 1]\)。
子串长度为 \(1\) 时,如果字符 \(s[i]\) 为 *,则 \(dp[i][i]\) 为 true,否则为 false。
子串长度大于 \(1\) 时,如果满足下面任意一种情况,则 \(dp[i][j]\) 为 true:
- 子串 \(s[i..j]\) 的左边界为
(或*,且右边界为*或),且 \(s[i+1..j-1]\) 为有效括号字符串; - 子串 \(s[i..j]\) 中的任意下标 \(k\),如果 \(s[i..k]\) 为有效括号字符串,且 \(s[k+1..j]\) 为有效括号字符串,则 \(s[i..j]\) 为有效括号字符串。
时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\)。其中 \(n\) 为字符串 s 的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
方法二:贪心 + 两遍扫描
思考
区间 DP 是立方。从左把 ( 与 * 都当可匹配存量,遇 ) 必须能减;再从右对 ) 与 * 同样扫一遍。两遍都过则左右都能配平。
两遍扫描,第一遍从左往右,确定每一个右括号都可以成功配对,第二遍从右往左,确定每一个左括号都可以成功配对。
时间复杂度 \(O(n)\),空间复杂度 \(O(1)\)。其中 \(n\) 为字符串 s 的长度。
相似题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |