前端刷题路-Day55:有效的括号(题号20)

262 阅读1分钟

这是我参与更文挑战的第18天,活动详情查看: 更文挑战

有效的括号(题号20)

题目

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

示例 4:

输入:s = "([)]"
输出:false

示例 5:

输入:s = "{[]}"
输出:true

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

链接

leetcode-cn.com/problems/va…

解释

这题啊,这题是经典垃圾小题目。

一开始笔者想多了,以为不一定非得按照顺序来,于是进行了一波操作,结果这题压根就不支持这样的格式,比方说([)],这也可以构成两个完整的括号,只是顺序上不一样。

结果这题压根没有这么复杂,这种情况不需要考虑,直接GG,题目认为对的情况是这样的:([{}]{}),不存在包裹一半的情况发生。

那这样做就简单了,直接一个栈就搞定了,搞一个对象,确定括号们的匹配关系:

obj = {
  ')': '(',
  ']': '[',
  '}': '{'
}

之后如果是左括号统一推入到栈中,如果遇到右括号,和栈中的最后一个元素匹配,如果不是一对,返回false,如果是一对,就去掉栈中的最后一个元素。

很简单的操作,这也是笔者第一时间想到的答案,其实这类匹配括号的题目基本上都可以用栈来操作,方便快捷。

自己的答案(栈)

var isValid = function(s) {
  var stack = []
      obj = {
        ')': '(',
        ']': '[',
        '}': '{'
      }
  for (const symbol of s) {
    if (!obj[symbol]) {
      stack.push(symbol)
    } else {
      if (obj[symbol] !== stack.pop()) return false
    }
  }
  return stack.length === 0
};

代码也就像解释中说的那样,用栈来进行括号的匹配。

需要注意的是最后一行代码,这里为什么不直接返回true呢?其实是因为即使前面完成了所有的匹配,最后的结果也还是会剩几个单独的括号,这样的用例是不行的。

更好的答案(栈 + 剪枝)

上面这种解法其实是可以进行剪枝操作的,如果字符串的长度为奇数,显然在这题中是不能通过的,所以可以在开头直接进行判断,如果是奇数,直接返回false

这样还避免了无意义的运算,官方答案就有这样的判断👇:

var isValid = function(s) {
  if (s.length % 2 === 1) return false
  var stack = []
      obj = {
        ')': '(',
        ']': '[',
        '}': '{'
      }
  for (const symbol of s) {
    if (!obj[symbol]) {
      stack.push(symbol)
    } else {
      if (obj[symbol] !== stack.pop()) return false
    }
  }
  return stack.length === 0
};

更好的答案(正则 + 递归)

严格意义上来说,该方法不是更好的答案,因为不管是运行时间还是内存占用上都比不过前两种方法,不过笔者觉得很有意思,还是放在这里了。

先看看代码👇:

var isValid = function(s) {
  while (s.includes('()') || s.includes('[]') || s.includes('{}')) {
    if (s.includes('()')) {
      s = s.replace('()', '')
    }
    if (s.includes('[]')) {
      s = s.replace('[]', '')
    }
    if (s.includes('{}')) {
      s = s.replace('{}', '')
    }
  }
  return s.length === 0
};

这方法看起来是不是有点暴力,但又感觉有点意思。

逻辑很简单,如果遇到匹配的括号,就直接替换掉,就这样一直迭代,迭代到字符串中没有成对的括号为止,最后返回字符串的长度,如果长度长度为0,则证明是符合条件的字符串,如果不为0,证明该字符串有问题,返回false

或者可以直接去掉迭代里面的判断,替换就完事了,哪管那么多,再加上一点剪枝👇:

var isValid = function(s) {
  if (s.length % 2 === 1) return false
  while (s.includes('()') || s.includes('[]') || s.includes('{}')) {
    s = s.replace('()', '')
    s = s.replace('[]', '')
    s = s.replace('{}', '')
  }
  return s.length === 0
};

运行时间有了些许提升,从原来的5%上升到了15%,但内存占用毫无变化,依旧是5%。

这种答案仅仅是提供思路,真正用这种办法可能会被喷个半死。



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)

有兴趣的也可以看看我的个人主页👇

Here is RZ