原文:从一道面试题谈起,作者:360奇舞团 刘观宇

题目:

创建一个函数来判断给定的表达式中的大括号是否闭合,返回 true/false,对于空字符串,返回 true

var expression = "{{}}{}{}"
var expressionFalse = "{}{{}" function isBalanced (exp) {}

题目本身比较简单。看完文章实现,感觉实现思路很重要,更要能举一反三。

虽然大学的时候也学了数据结构,栈,但应用的很少,看完本文,对栈在实际工作中的应用,也有了全新的思路与看法。

实现

以下是应用数据结构栈的特点,先进先出,在 js 中用数组模拟实现的代码。

function isBalanced (exp) {
if (!(exp + '').trim()) {
return true;
} let stack = [];
let arr = exp.trim().split('');
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (item === '{') {
stack.push(item);
} else if (item === '}') {
if (!stack.length) {
return false;
}
stack.pop();
}
} return stack.length === 0
} // test
var expT = '{{}}{}{}';
var expF = '{}{{}' console.log(isBalanced('')); // true
console.log(isBalanced(expT)); // true
console.log(isBalanced(expF)); // false

利用栈先进先出的特点,找到一个 { ,就压入栈中;而找到一个 } ,如栈中是空的,则直接返回false,否则就从栈中弹出一个 { 。循环结束后,通过判断栈是否为空,判断字符中中 {} 是否闭合。

举一反三

题目一:实现函数 isBalanced, 用 true/false 表示给定的字符串的括号是否平衡(一一对应)。注意要支持三种类型的括号,带有交错括号的字符串应该返回false

isBalanced('(foo { bar (baz) [boo] })') // true
isBalanced('foo { bar { baz }') // false
isBalanced('foo { (bar [baz] } )') // true

实现思路和上面的是一致的,也是利用栈的特性。

过滤无效字符,每一种有括号有一种唯一的左括号与之对应。

实现:

function isBalanced (exp) {
if (!(exp + '').trim()) {
return true;
} let stack = [];
let signObj = {
'{': '}',
'(': ')',
'[': ']'
}; let arr = exp.trim().split('');
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (signObj.hasOwnProperty(item)) { // stack 中只压入指定符号
stack.push(item);
} else if (Object.values(signObj).includes(item)) { // 针对指定符号的值比对,得到对象key
let leftSign;
for(let key in signObj) {
if (item === signObj[key]) {
leftSign = key;
}
}
if (stack[stack.length - 1] !== leftSign) {
return false;
}
stack.pop();
}
} return stack.length === 0;
} // test
console.log(isBalanced('')); // true
console.log(isBalanced('(foo { bar (baz) [boo] })')); // true
console.log(isBalanced('foo { bar { baz }')); // false
console.log(isBalanced('foo { (bar [baz] } )')); // false

通过对象的键值对过滤掉无效字符,再通过值找到对应的key,和栈中最后压入的进行比较,不相等就是不匹配直接false,相等就表示匹配,然后把栈中的最后的弹出。

通过map和es6的语法,可以把代码写的一气呵成

function isBalanced (exp) {
if (!(exp + '').trim()) {
return true;
} const map = new Map([
['{', '}'],
['(', ')'],
['[', ']']
]); let stack = [];
let arr = exp.trim().split('');
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (map.has(item)) {
stack.push(item);
} else if ([...map.values()].includes(item)) {
if (stack[stack.length - 1] !== [...map.entries()].filter(el => el[1] === item).pop().shift()) {
return false;
}
stack.splice(stack.length - 1, 1);
}
} return stack.length === 0
}

说明:[...map.entries()]的结果是二维数组,这个看懂了,就比较容易理解了

[
['{', '}'],
['(', ')'],
['[', ']']
]

题目二:要求严格限制括号的顺序,即中括号外围只能是大括号,内部只能是小括号。也即:括号只能以大括号、中括号、小括号的顺序只能前面的包含后面的,不能后面的包含前面的,用代码来表示一下

isStrictBalanced('foo { bar (baz) [boo] }') // true

isStrictBalanced('(foo { bar (baz) [boo] })') // false

实现思路,在入栈的时候判断优先级。

怎么判断优先级,利用字符比较。这是我没想到的,都不知道这三个的具体charCodeAt值。(_)

"{".charCodeAt() === 123,"[".charCodeAt() === 91,"(".charCodeAt() === 40

实现:

function isBalanced (exp) {
if (!(exp + '').trim()) {
return true;
} let stack = [];
let signObj = {
'{': '}',
'[': ']',
'(': ')'
};
let keys = Object.keys(signObj); let arr = exp.trim().split('');
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (signObj.hasOwnProperty(item)) {
// stack 中只压入指定符号,并且判断优先级
// "{".charCodeAt() === 123,"[".charCodeAt() === 91,"(".charCodeAt() === 40
if (stack.length) {
let pop = stack.slice().pop()
if (pop < item) {
return false
}
}
stack.push(item);
} else if (Object.values(signObj).includes(item)) { // 针对指定符号的值比对
let leftSign;
for(let key in signObj) {
if (item === signObj[key]) {
leftSign = key;
}
}
if (stack[stack.length - 1] !== leftSign) {
return false;
}
stack.pop();
}
} return stack.length === 0;
} // test
console.log(isBalanced('')); // true
console.log(isBalanced('foo { bar (baz) [boo] }')); // true
console.log(isBalanced('(foo { bar (baz) [boo] })')); // false
console.log(isBalanced('(foo [bar])')); // false
console.log(isBalanced('[foo (bar)]')); // true
console.log(isBalanced('[foo (bar)] {bar [boo] }')); // true

思路通了,用map和es6实现其实也很容易,就不浪费笔墨了。

isBalanced函数实现的更多相关文章

  1. Python 小而美的函数

    python提供了一些有趣且实用的函数,如any all zip,这些函数能够大幅简化我们得代码,可以更优雅的处理可迭代的对象,同时使用的时候也得注意一些情况   any any(iterable) ...

  2. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  3. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

  4. C++对C的函数拓展

    一,内联函数 1.内联函数的概念 C++中的const常量可以用来代替宏常数的定义,例如:用const int a = 10来替换# define a 10.那么C++中是否有什么解决方案来替代宏代码 ...

  5. 菜鸟Python学习笔记第一天:关于一些函数库的使用

    2017年1月3日 星期二 大一学习一门新的计算机语言真的很难,有时候连函数拼写出错查错都能查半天,没办法,谁让我英语太渣. 关于计算机语言的学习我想还是从C语言学习开始为好,Python有很多语言的 ...

  6. javascript中的this与函数讲解

    前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码, ...

  7. 复杂的 Hash 函数组合有意义吗?

    很久以前看到一篇文章,讲某个大网站储存用户口令时,会经过十分复杂的处理.怎么个复杂记不得了,大概就是先 Hash,结果加上一些特殊字符再 Hash,结果再加上些字符.再倒序.再怎么怎么的.再 Hash ...

  8. JS核心系列:浅谈函数的作用域

    一.作用域(scope) 所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的. function scope(){ var foo = "global&quo ...

  9. C++中的时间函数

    C++获取时间函数众多,何时该用什么函数,拿到的是什么时间?该怎么用?很多人都会混淆. 本文是本人经历了几款游戏客户端和服务器开发后,对游戏中时间获取的一点总结. 最早学习游戏客户端时,为了获取最精确 ...

随机推荐

  1. P3834 【模板】可持久化线段树 1(主席树)

    #include <bits/stdc++.h> #define read read() #define up(i,l,r) for(int i = (l);i <= (r);i++ ...

  2. vue组件实现查看大图效果

    使用的index.vue代码 <template> <img :src="imgUrl" @click="clickImg($event)"& ...

  3. Codeforces 1093 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 GGG题手速慢了没有在比赛的时候码出来233,FFF题居然没想出来? 五道题滚粗. 先谈谈其他几道题. A题 传送门 不小心看错题 直接看奇 ...

  4. vue中使用promise.all发送多个请求

    1.创建两个promise,在promise中使用axios 2.调用Promise.all([p1,p2]).then(res=>{}).catch(err=>{})方法 代码如下: & ...

  5. matlab 向量场线积分

    syms t x y z F x=cos(t); y=sin(t); z=*sin(t)^-; F=[x^*y , (/)*x^,x*y ] ; %场函数 V=[diff(x,t),diff(y,t) ...

  6. 内联/块级元素的宽高及margin/padding的说明 |||||| 为何img、input等内联元素可以设置宽、高

    1,内联非替换元素设置宽高是无效的,设置margin时,左右有效,上下无效.设置padding时,左右有效,而上下padding比较奇葩,内联非替换元素的上下padding会在元素内容盒不动的情况下上 ...

  7. dj cookie与session 2

    def login_session(request): if request.method == "POST": user = request.POST.get("use ...

  8. 最全js表单验证

    /***************************************************************** 表单校验工具类 (linjq) ***************** ...

  9. 学习devexpresschartControl控件

    devexpress官网chart:https://documentation.devexpress.com/WindowsForms/8117/Controls-and-Libraries/Char ...

  10. $.contains(a,b)

    jQuery.contains()函数用于判断指定元素内是否包含另一个元素. 简而言之,该函数用于判断另一个DOM元素是否是指定DOM元素的后代. 该函数属于全局jQuery对象. 语法 jQuery ...