leetcode:678. 有效的括号字符串

题目

给定一个只包含三种字符的字符串:()*,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:

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

示例:

  1. 输入: "()"
  2. 输出: True
  1. 输入: "(*)"
  2. 输出: True
  1. 输入: "(*))"
  2. 输出: True

解答 & 代码

解法 0:递归回溯(超时)

  1. class Solution {
  2. private:
  3. bool backTrace(string s, int idx, int leftCnt, int rightCnt)
  4. {
  5. // 递归结束条件 1:字符串遍历结束,返回左括号数是否等于右括号数
  6. if(idx == s.size())
  7. return leftCnt == rightCnt;
  8. // 如果之前已遍历的字符串中的右括号数 > 左括号数,肯定不合法,返回 false
  9. if(rightCnt > leftCnt)
  10. return false;
  11. // 如果当前是左括号
  12. if(s[idx] == '(')
  13. return backTrace(s, idx + 1, leftCnt + 1, rightCnt);
  14. // 如果当前是右括号
  15. else if(s[idx] == ')')
  16. return backTrace(s, idx + 1, leftCnt, rightCnt + 1);
  17. // 如果当前是星号
  18. else if(s[idx] == '*')
  19. return backTrace(s, idx + 1, leftCnt + 1, rightCnt) ||
  20. backTrace(s, idx + 1, leftCnt, rightCnt + 1) ||
  21. backTrace(s, idx + 1, leftCnt, rightCnt);
  22. else
  23. return false;
  24. }
  25. public:
  26. bool checkValidString(string s) {
  27. return backTrace(s, 0, 0, 0);
  28. }
  29. };

解法二:栈

[简单] 20. 有效的括号
类似上面这道题,只是多了星号要处理

左括号栈 + 星号栈(两个栈都存储对应的下标)

  1. 遍历字符串
    1. 如果当前是左括号,则将当前下标存入左括号栈
    2. 如果当前是星号,则将当前下标存入星号栈
    3. 如果当前是右括号
      1. 优先和左括号匹配,及如果左括号栈不为空,则弹出左括号栈栈顶元素
      2. 若左括号栈为空,则和星号匹配(将星号当作左括号)。如果星号栈不为空,则弹出星号栈栈顶
      3. 如果两个栈都为空,则无法匹配,直接返回 false
  2. 匹配剩余左括号,即如果左括号栈不为空,则将星号当作右括号,和左括号栈中的剩余左括号匹配
    1. 如果星号栈为空,则无法匹配,直接返回 false
    2. 如果星号栈栈顶下标小于左括号栈栈顶下标,则无法匹配,直接返回 false
    3. 否则,能够匹配,弹出两个栈栈顶元素
  3. 最后左括号栈为空,返回 true(不论星号栈是否为空,若星号栈还有元素,则剩余星号当作空字符即可)

    1. class Solution {
    2. public:
    3. bool checkValidString(string s) {
    4. stack<int> leftS; // 存储左括号对应下标的栈
    5. stack<int> starS; // 存储星号对应下标的栈
    6. // 1. 遍历字符串
    7. for(int i = 0; i < s.size(); ++i)
    8. {
    9. // 1.1 如果当前是左括号,则将当前下标存入左括号栈
    10. if(s[i] == '(')
    11. leftS.push(i);
    12. // 1.2 如果当前是星号,则将当前下标存入星号栈
    13. else if(s[i] == '*')
    14. starS.push(i);
    15. // 1.3 如果当前是右括号
    16. else if(s[i] == ')')
    17. {
    18. // a. 优先和左括号匹配,及如果左括号栈不为空,则弹出左括号栈栈顶元素
    19. if(!leftS.empty())
    20. leftS.pop();
    21. // b. 若左括号栈为空,则和星号匹配(将星号当作左括号)
    22. // 如果星号栈不为空,则弹出星号栈栈顶
    23. else if(!starS.empty())
    24. starS.pop();
    25. // c. 如果两个栈都为空,则无法匹配,直接返回 false
    26. else
    27. return false;
    28. }
    29. }
    30. // 2. 将星号当作右括号,和左括号栈中的剩余左括号匹配
    31. while(!leftS.empty())
    32. {
    33. // 如果左括号栈不为空,而星号栈为空 or 星号栈栈顶下标小于左括号栈栈顶下标
    34. // 则无法匹配,直接返回 fasle
    35. if(starS.empty() || starS.top() < leftS.top())
    36. return false;
    37. // 否则,能够匹配,弹出两个栈栈顶
    38. leftS.pop();
    39. starS.pop();
    40. }
    41. // 3. 最后左括号栈为空,返回 true
    42. return true;
    43. }
    44. };

    复杂度分析:设字符串 s 长为 N

  • 时间复杂度 O(N):
  • 空间复杂度 O(N):

执行结果:

  1. 执行结果:通过
  2. 执行用时:0 ms, 在所有 C++ 提交中击败了 100.00% 的用户
  3. 内存消耗:6 MB, 在所有 C++ 提交中击败了 68.67% 的用户