有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
示例 4:
输入:s = “([)]”
输出:false
示例 5:
输入:s = “{[]}”
输出:true
提示:
1 <= s.length <= 104 s 仅由括号 ‘()[]{}’ 组成
1.分析
根据题意我们可以得出:
1.有效的字符串长度一定是偶数,否则无效
2.右括号前边必须是对应的左括号才有效,否则无效
3.我们可以使用栈来看数据是否对应,比如,遇左括号就压入栈
4.如遇右括号,弹出栈顶,两者对应,则抵消
5.最后栈中还有数据,证明没有全部抵消,字符串无效
2.题解
下面我们使用两个方法来完成这道题
解法1 - 使用 es6的 map
var isValid = function(s) {
let l = s.length
if (l % 2 !== 0 ) { return false } // 1.字符串长度不是偶数直接返回 false
let map = new Map([['}', '{'], [')', '('], [']', '[']])
// 2.使用 map 将括号映射成如下键值对(因为我们通过右括号判断左括号):
// Map(3) {')' => '(', ']' => '[', '}' => '{'}
let stack = []
for (let i of s) { // 循环遍历当前字串
if (map.get(i)) { // 3.判断有无当前键对应的值,因为我们是通过右括号判断左括号,但字串顺序是从左到右的,所以前几轮判断会走 else
if (stack[stack.length - 1] === map.get(i)) { // 4.判断右括号时,找对应括号需从数组倒序比较,即从最后一个元素依次开始
stack.pop() // 4.如果相等即弹出
} else {
return false // 4.否则返回false开始下一轮循环
}
} else {
stack.push(i) // 3.如字串'[({})]'前三轮会将'[({'写入数组
}
}
return !stack.length;
}
走过的坑:
1.map 用法
map 生成键值对,和数组的转换
此例中,要想生成 {’)’ => ‘(’, ‘]’ => ‘[’, ‘}’ => ‘{’}的映射关系,需要在 new Map()中嵌套数组,加一个’[ ]’
2.for in 和 for of 区别
for…of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象, 因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句,for-of循环不支持普通对象,不建议使用 for-in 属性遍历数组等,因为,for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。
如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法:
Array pop()方法
pop() 方法移除数组的最后一个元素,并返回该元素。
解法2 - switch case 或者 if 按条件判断
把左括号全部推入栈中,到右括号时依次从栈顶弹出比较
let isValid = function(s) {
let l = s.length;
if (l % 2 !== 0) { return false };
let stack = []
for (let i of s) {
switch (i) {
case '{':
case '[':
case '(':
stack.push(i);
break;
case '}':
if(stack.pop() !== '{') return false;
break;
case ']':
if(stack.pop() !== '[') return false;
break;
case ')':
if(stack.pop() !== '(') return false;
break;
}
}
return !stack.length;
}