[JS基础] 有效括号的`多个场景`~~

611 阅读4分钟

目录

  1. 有效的括号 (if..else 实现)
  2. 有效的括号 (switch..case 实现)
  3. 有效的括号 (对象分支 实现)
  4. 有效括号的多个场景
  5. 括号匹配 -- 栈解决

一 有效的括号 (if..else 实现)

思路: 遍历字符串时,如果遇到左括号,就把对应的右括号保存到数组当中.

/**
 * @param {string} 字符串
 * @return {boolean} 布尔值
 */
var isValid1 = function (str) {
  // 如果 item 是 ( 就在stack中存入 [')'], 如果 item 是 [ 就在stack中存入 [']']
  const stack = []; // 数组中每一次遍历后,最多只有一个元素, 不论,是否是有效括号,数组都会被清空
  for (let i = 0; i < str.length; i++) {
        let item = str[i];
        if(item === '(') {
            stack.push(')');
        } else if(item === '[') { 
            stack.push(']');
        } else if(item === '{') {
            stack.push('}');
        } else {
            // 这里的 stack 1, "[]" 时,是在数组中存了当前遍历的前半括号,对应的后半括号
            // 2, "[}"时, stack 存的是 [']'], 但是 当前的item为 } 所以不是有效括号.
            console.log('stack:',stack,'item:',item);
            if (item !== stack.pop()) { // 一个或多个时: "[}"时,或者 "[]()[}"时, 在判断时,已经把数组中的唯一元素pop出去,并且数组清空了.
              return false;
            }else{  // "[]" 时 或者 "[](){}[]()"时
              // return true // 这里不能return true, 否则只能判断一对括号是不是有效括号
            }
          console.log('stack---:',stack);
        }
  }
    console.log('stack---:',stack);
    // 非有效括号在遍历中就return出去了
    // 如果都是有效括号,遍历完成后, 走到这里就肯定是 有效括号, 但是,除了多个左括号的种种情况 "[[" '((' "{{" "[[[.."
    // return true; // 除了上面 "[[" '((' "{{" "[[[.." 类似的情况有问题,其他情况都可以  return true;
    return stack.length === 0;
};
// 第一次遍历把左括号,对应的右括号保存到数组中.
// 第二次遍历,拿第二次遍历的item与数组当中的元素比较,并且利用pop的特性把数组中唯一的元素清空了,如果相等就是有效括号,如果不相等就是 非有效括号
var str = "[[[[";
isValid1(str);
// stack---: (4) [']', ']', ']', ']']
false

二 有效的括号 (switch..case 实现)

写这个其实没啥意义, 分支语句的另外一种写法 这里可以用函数式的方式来写

R.cond()

也是一样的.

var isValid = function (str) {
  const stack = [];
  for (let i = 0; i < str.length; i++) {
    let item = str[i];
    switch (item) {
      case '(':
        stack.push(')');
        break;
      case '[':
        stack.push(']');
        break;
      case '{':
        stack.push('}');
        break;
      default:
        if (item !== stack.pop()) {
          return false;
        }
    }
  }
  return stack.length === 0;
};
var str = '[]()';
var str1 = '[[['
var str2 = '][]()'
isValid(str); // true
isValid(str1) // false
isValid(str2) // false

对象分支 实现

var isValid = function(str) {
    const stack = [], 
        map = {
            "(":")",
            "{":"}",
            "[":"]"
        };
    for(const item of str) {
        if(item in map) {
            stack.push(item);
            continue;
        };
        if(map[stack.pop()] !== item) return false;
    }
    return !stack.length;
};
var str = '[]()';
var str1 = '[[['
var str2 = '][]()'
isValid(str)

四 有效括号的多个场景

1) 多个左括号时, ']' , ']]' , ')))' , '}}}}'

var str = "[[[[";

isValid1(str);

// 此时 stack为: [']', ']', ']', ']'];

遍历时,不断的push到数组当中,对应的右括号,比如,有4个左括号,就push4次 右括号到数组当中, 遍历完成后, 直接走到最后一步, 此时数组中存了4个右括号, return stack.length === 0 为False

步骤 var str = "[[[[";

  1. 第一次遍历, push 到 stack 中为 [']']
  2. 第二次遍历, 继续 push 到 stack 中为 [']',']']
  3. 第三次遍历, 继续 push 到 stack 中为 [']',']',']']
  4. 第四次遍历, 继续 push 到 stack 中为 [']',']',']',']']
  5. 此时 stack[']',']',']',']']
  6. 执行 return stack.length === 0;
  7. 返回 false

2) 一或多个非有效括号 '[}'时, 或者 "[}"时

str = '[}';
// 关键走这里
if (item !== stack.pop()) { 
     return false;
}

image.png

一个或多个时: "[}"时,或者 "[}()[}"时, 在判断时,已经把数组中的唯一元素pop出去,并且数组清空了.

直到遇到的下一下偶数索引的括号不是对应的右括号时,就直接return false出去这个函数,结束循环跳出函数.

比如当str = '[}' 时 ,在第一次遍历时, item为 [ 时 数组stack中存入 [']'],然后,在第二次遍历时,比较的当前item为 } 号, stack.pop出的元素为 ] 号,所以就直接返回 false

步骤

  1. 第一次遍历, push 到 stack 中为 [']']
  2. 第二次遍历, 比较 item 此时为 '}' 与 stack.pop的返回值 ']' 不相等. stack.pop()时,并且把数组清空了.
  3. return false 跳出函数,返回false

3) 一个或多个有效括号时, "[]" 时 或者 "{}"时

var str = "[](){}[]()";

isValid1(str);

image.png

步骤 var str = "[](){}[]()";

  1. 第一次遍历, push 到 stack 中为 [']']
  2. 第二次遍历, 在比较item与stack中的元素时, stack.pop(),并且把数组清空了.
  3. 第三次遍历, push 到 stack 中为 [')']
  4. 第四次遍历, 在比较item与stack中的元素时, stack.pop(),并且把数组清空了.
  5. 直到 "{}" 所有的都遍历完成.
  6. 此时的stack为空数组 []
  7. 执行 return stack.length === 0;
  8. 返回 true

4) 一个或多个有效括号时, "[]" 时 或者 "[{([])}]"时

利用 棧 的特性, push 和 pop 来处理这种场景

var str = "[{([])}]";
isValid1(str);

image.png

括号匹配 -- 栈解决

括号匹配使用栈解决的经典问题。

题意其实就像我们在写代码的过程中,要求括号的顺序是一样的,有左括号,相应的位置必须要有右括号。如果还记得编译原理的话,编译器在 词法分析的过程中处理括号、花括号等这个符号的逻辑,也是使用了栈这种数据结构

1) 有效括号-场景回顾

第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false

第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false

第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。

分析完之后,代码其实就比较好写了,

但还有一些技巧,在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了!

参考

总结

  • 有效括号: 遍历是必须的,在遍历到奇数item时,我们就可以知道偶数item是啥了, 然后,进行比较即可.
  • 遍历字符串的方式: forfor...of
  • 括号匹配使用栈解决的经典问题。