一、题目内容 简单中等困难
给定一个只包含三种字符的字符串:(
,)
和*
,写一个函数来检验这个字符串是否为有效字符串。
有效字符串具有如下规则:
任何左括号 (
必须有相应的右括号 )
。
任何右括号)
必须有相应的左括号 (
。
左括号 (
必须在对应的右括号之前 )
。*
可以被视为单个右括号 )
,或单个左括号 (
,或一个空字符串。
一个空字符串也被视为有效字符串。
示例1:
输入:
"()"
输出: True
示例2:
输入:
"(*)"
输出: True
示例3:
输入:
"(*))"
输出: True
注意:
- 如果遇到左括号,则未匹配的左括号数量加 1
- 如果遇到右括号,则需要有一个左括号和右括号匹配,匹配成功后,未匹配的左括号数量减 1
- 如果遇到星号,由于星号可以看成左括号、右括号、空字符,因此未匹配的左括号数量可能加 1,减 1,或不变
基于上述结论,可以在遍历的过程中维护未匹配的左括号数量可能的最大值、最小值
- 如果遇到左括号,则将最大值,最小值都加 1
- 如果遇到右括号,则将最大值、最小值都减 1
- 如果遇到星号,则将最大值加 1,最小值减 1
注意,未匹配的左括号数量必须非负,因此最大值小于 0 时,说明没有左括号可以跟右括号匹配了,返回 false
当最小值为 0 时,不应将最小值继续减小,以确保最小值非负。
遍历结束时,所有的左括号都应和右括号匹配,因此只有当最小值为 0 时,字符串 s 才是有效的括号字符串。
三、具体代码
/**
* @param {string} s
* @return {boolean}
*/
var checkValidString = function (s) {
let min = max = 0;
for (let i = 0; i < s.length; i++) {
const c = s[i];
if (c === '(') {
min += 1;
max += 1;
} else if (c === ')') {
min = min === 0 ? 0 : min - 1;
max -= 1;
if (max < 0) return false;
} else if (c === '*') {
min = min === 0 ? 0 : min - 1;
max += 1;
}
}
return min === 0;
};
/**
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/