[LeetCode] 678. Valid Parenthesis String

Given a string s containing only three types of characters: '('')' and '*', return true if s is valid.

The following rules define a valid string:

  • Any left parenthesis '(' must have a corresponding right parenthesis ')'.
  • Any right parenthesis ')' must have a corresponding left parenthesis '('.
  • Left parenthesis '(' must go before the corresponding right parenthesis ')'.
  • '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string "".

Example 1:

Input: s = "()"
Output: true

Example 2:

Input: s = "(*)"
Output: true

Example 3:

Input: s = "(*))"
Output: true

Constraints:

  • 1 <= s.length <= 100
  • s[i] is '('')' or '*'.

有效的括号字符串。

给你一个只包含三种字符的字符串,支持的字符类型分别是 '('、')' 和 '*'。请你检验这个字符串是否为有效字符串,如果是有效字符串返回 true 。

有效字符串符合如下规则:

任何左括号 '(' 必须有相应的右括号 ')'。
任何右括号 ')' 必须有相应的左括号 '(' 。
左括号 '(' 必须在对应的右括号之前 ')'。
'*' 可以被视为单个右括号 ')' ,或单个左括号 '(' ,或一个空字符串。
一个空字符串也被视为有效字符串。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-parenthesis-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给一个字符串,里面有左括号右括号和星号,请判断 input 字符串是否是一个合法的括号组合。其中星号是一个通配符,可以表示左括号右括号或者星号。做这个题之前需要先复习一下20题这道题我提供三种做法,第一种扫描两遍,第二种扫描一遍,第三种会用到栈。

首先是扫描两遍的做法。第一遍从左往右,第二遍从右往左。第一遍扫描的时候,把星号当做左括号,所以遇到左括号和星号的时候就 left++,遇到右括号就 left--;过程中只要 left 小于 0 就 return false,说明右括号多而且是星号没法补救的。第一遍扫描完毕之后如果 left == 0 则直接 return true,因为左括号 + 星号可以和右括号互相抵消。如果 left 大于0 也不用担心,因为这里面应该是存在一些星号的。

第二遍扫描的时候是从右往左,此时把星号当做右括号,如果看到右括号或者星号就 right++,看到左括号就 right--;跟第一遍一样,过程中只要 right 小于 0 了就 return false,说明左括号多到无法补救。遍历结束则 return true。

一个疑问:如果第一遍里面只是左括号比较多,left 不也是大于 0 吗?没问题,第二遍扫描的时候,这种 case 会被抓出来(因为 right 会小于 0 了)从而 return false。

时间O(n)

空间O(1)

Java实现

 1 class Solution {
 2     public boolean checkValidString(String s) {
 3         int left = 0;
 4         int right = 0;
 5         int n = s.length();
 6         // scan from left to right
 7         for (int i = 0; i < n; i++) {
 8             if (s.charAt(i) == '(' || s.charAt(i) == '*') {
 9                 left++;
10             } else {
11                 left--;
12             }
13             if (left < 0) {
14                 return false;
15             }
16         }
17         if (left == 0) {
18             return true;
19         }
20 
21         // scan from right to left
22         for (int i = n - 1; i >= 0; i--) {
23             if (s.charAt(i) == ')' || s.charAt(i) == '*') {
24                 right++;
25             } else {
26                 right--;
27             }
28             if (right < 0) {
29                 return false;
30             }
31         }
32         return true;
33     }
34 }

 

JavaScript实现

 1 /**
 2  * @param {string} s
 3  * @return {boolean}
 4  */
 5 var checkValidString = function(s) {
 6     let left = 0;
 7     let right = 0;
 8     let len = s.length;
 9     for (let i = 0; i < len; i++) {
10         if (s.charAt(i) == '(' || s.charAt(i) == '*') {
11             left++;
12         } else {
13             left--;
14         }
15         if (left < 0) {
16             return false;
17         }
18     }
19     if (left == 0) {
20         return true;
21     }
22 
23     for (let i = len - 1; i >= 0; i--) {
24         if (s.charAt(i) == ')' || s.charAt(i) == '*') {
25             right++;
26         } else {
27             right--;
28         }
29         if (right < 0) {
30             return false;
31         }
32     }
33     return true;
34 };

 

接下来是扫描一遍的做法。这里我们设置两个变量cmax和cmin,代表需要被match的左括号的上限和下限。

当遇到一个左括号的时候,cmax和cmin都需要++,因为你需要为这个左括号找一个配对

当遇到一个右括号的时候,自然是cmax--,cmin也需要--,但是如果cmin小于0了,说明右括号更多了,此时我们为了不让他小于0,我们取的是0和cmin的较大值

当遇到一个星号的时候,因为他是通配符,所以如果当做左括号的话,cmax就++,如果当做右括号的话,cmin就--,因为他可以去抵消一个左括号

最后判断的时候,如果cmax小于0就return false,因为cmax只有在遇到右括号的时候才--,说明右括号多到无法被抵消。

时间O(n)

空间O(1)

Java实现

 1 class Solution {
 2     public boolean checkValidString(String s) {
 3         int cmin = 0;
 4         int cmax = 0;
 5         for (int i = 0; i < s.length(); i++) {
 6             char c = s.charAt(i);
 7             if (c == '(') {
 8                 cmax++;
 9                 cmin++;
10             } else if (c == ')') {
11                 cmax--;
12                 cmin = Math.max(cmin - 1, 0);
13             } else {
14                 cmax++;
15                 cmin = Math.max(cmin - 1, 0);
16             }
17             if (cmax < 0) {
18                 return false;
19             }
20         }
21         return cmin == 0;
22     }
23 }

 

第三种解法用到栈。这里我们需要两个栈,一个记录左括号的 index,一个记录星号的 index,这里我们分别叫做 stack1 和 stack2。

  • 遇到左括号,把 index 入栈 stack1
  • 遇到右括号,
    • 如果 stack1 不为空,弹出栈顶元素,说明有一个左右括号的配对
    • 如果 stack1 为空,看看 stack2 是否为空 - 是否有星号,如有,则用星号抵消左括号
    • 如果此时 stack1 和 stack2 都为空,return false
  • 遇到星号,放入 stack2

此时我们可以处理所有左括号,但是 stack1 和 stack2 可能不为空,此时我们需要判断 stack2 里面的星号是否能抵消 stack1 里剩余未配对的括号。注意这里配对的原则是如果括号的 index 大于星号的 index,说明这个括号是不能被抵消的,因为他出现在了一个星号之后,星号只能抵消之前的括号。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public boolean checkValidString(String s) {
 3         Stack<Integer> operators = new Stack<>();
 4         Stack<Integer> stars = new Stack<>();
 5         for (int i = 0; i < s.length(); i++) {
 6             // 遇到左括号
 7             if (s.charAt(i) == '(') {
 8                 operators.push(i);
 9             }
10             // 遇到右括号
11             else if (s.charAt(i) == ')') {
12                 // 如果有左括号就抵消
13                 if (operators.size() > 0) {
14                     operators.pop();
15                 }
16                 // 如果有星号就抵消
17                 else if (stars.size() > 0) {
18                     stars.pop();
19                 } else {
20                     return false;
21                 }
22             }
23             // 星号
24             else {
25                 stars.push(i);
26             }
27         }
28 
29         while (operators.size() > 0 && stars.size() > 0) {
30             if (operators.peek() > stars.peek()) {
31                 return false;
32             }
33             operators.pop();
34             stars.pop();
35         }
36         return operators.size() == 0;
37     }
38 }

 

相关题目

20. Valid Parentheses

678. Valid Parenthesis String

1111. Maximum Nesting Depth of Two Valid Parentheses Strings

921. Minimum Add to Make Parentheses Valid

1541. Minimum Insertions to Balance a Parentheses String

LeetCode 题目总结

posted @ 2020-04-01 13:39  CNoodle  阅读(229)  评论(0编辑  收藏  举报