JavaScript数据结构之栈实例用法


Posted in Javascript onJanuary 18, 2019


先来看一道题

Leetcode 32 Longest Valid Parentheses (最长有效括号)

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"

示例 2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

这道题可以用动态规划来做,也能用简洁明了的栈来解决。

什么是栈?

栈是一种先进后出(LIFO)的有序集合,新添加的元素在栈顶,旧元素在栈底。

以下图为例,1、2、3、4、5、6、7先后进栈:

JavaScript数据结构之栈实例用法

创建栈

创建一个类来表示栈:

class Stack {
 // 初始化类,创建数组 items 存放入栈元素
 constructor() {
  this.items = [];
 }
 // push 方法进行元素入栈(可同时入栈一或多个元素),无返回值
 push() {
  this.items.push(...arguments);
 }
 // pop 方法出栈一个元素,返回出栈元素
 pop() {
  return this.items.pop();
 }
 // peek 方法返回栈顶元素,不对栈本身做任何操作
 peek() {
  return this.items[this.items.length-1];
 }
 // size 方法返回栈内元素个数
 size() {
  return this.items.length;
 }
 // isEmpty 方法查看栈是否为空,返回布尔值
 isEmpty() {
  return this.items.length == 0;
 }
 // clear 方法清空栈,无返回值
 clear() {
  this.items = [];
 }
 // print 方法打印栈内元素
 print() {
  console.log(this.items.toString());
 }
}
 
// 测试 
let stack = new Stack();
stack.push(1,2,3,4);
stack.print(); // 1,2,3,4
stack.isEmpty(); // false
stack.size(); // 4
stack.pop(); // 4
stack.peek(); // 3
stack.clear();

注意

因为 JavaScript 的类内暂时无法定义私有成员,所以可以在类外访问到存储栈元素的数组 items,这个操作是很危险的。

stack.items; // [1, 2, 3, 4]

这时可以使用闭包和IIFE进行避免,这是一个很无奈的办法:

let Stack = (function () {
 // 使用 WeakMap 存储数组(数组存放进栈元素)
 let items = new WeakMap();
 class Stack {
  constructor() {
   items.set(this, []);
  }
  push() {
   items.get(this).push(...arguments);
  }
  // 其他方法
 }
 return Stack;
})();
 
let s = new Stack();
// 无法访问到 items
s.items; // undefined

WeakMap: WeakMap是类似Map的键值对集合,但WeakMap的键是弱引用的,只要不存在引用,垃圾回收机制就会回收掉占用的内存,相当于自动删除,而不用手动删除。

用栈解题

思路:

变量start存放有效括号起始下标,maxLen存放最大长度;

栈只存放左括号的下标,遇到左括号,将其下标存入栈中;

遇到右括号,若此时栈为空,跳过本次循环并更新start;若栈不为空,则栈顶元素出栈;

栈顶元素出栈后,若栈为空,则计算当前下标和start的距离,并更新maxLen;

栈顶元素出栈后,若栈不为空,则计算当前下标和栈顶存放的下标的距离,并更新maxLen;

循环遍历直至结束。

function test(str) {
 let stack = new Stack();
 let start = 0;
 let maxLen = 0;
 
 for(let i=0; i<str.length; i++) {
  // 如果是左括号,下标入栈
  if (str[i] == '(') {
   stack.push(i);
  } else {
   // 如果是右括号
   /* 栈内为空,说明本次有效括号匹配已结束,跳过本次循环并更新 start */
   if (stack.isEmpty()) {
    start = i+1;
    continue;
   } else {
    // 栈内不为空,则出栈一个左括号进行匹配
    stack.pop();
    // 栈顶元素出栈后,栈为空
    if (stack.isEmpty()) {
     // 根据当前下标和 start 去更新 maxLen
     maxLen = Math.max(maxLen, i-start+1);
    } else {
     // 栈不为空,根据当前下标和栈顶存放的下标去更新 maxLen
     maxLen = Math.max(maxLen, i-stack.peek());
    }
     
   }
  }  
 }
  
 return maxLen;
}
 
test('(()'); // 2
test(')()())'); // 4
Javascript 相关文章推荐
jQuery链式操作如何实现以及为什么要用链式操作
Jan 17 Javascript
jquery ajax实现下拉框三级无刷新联动,且保存保持选中值状态
Oct 29 Javascript
javascript中取前n天日期的两种方法分享
Jan 26 Javascript
jQuery结合AJAX之在页面滚动时从服务器加载数据
Jun 30 Javascript
如何在Linux上安装Node.js
Apr 01 Javascript
浅谈Vue内置component组件的应用场景
Mar 27 Javascript
JavaScript设计模式之责任链模式实例分析
Jan 16 Javascript
vuex 中插件的编写案例解析
Jun 10 Javascript
详解Vue中组件传值的多重实现方式
Aug 16 Javascript
openLayer4实现动态改变标注图标
Aug 17 Javascript
ant design vue嵌套表格及表格内部编辑的用法说明
Oct 28 Javascript
详解vue-cli项目在IE浏览器打开报错解决方法
Dec 10 Vue.js
Vue核心概念Action的总结
Jan 18 #Javascript
js取小数点后两位四种方法
Jan 18 #Javascript
jQuery移动端跑马灯抽奖特效升级版(抽奖概率固定)实现方法
Jan 18 #jQuery
jquery获取file表单选择文件的路径、名字、大小、类型
Jan 18 #jQuery
jQuery实现适用于移动端的跑马灯抽奖特效示例
Jan 18 #jQuery
js数组去重的方法总结
Jan 18 #Javascript
jQuery实现的3D版图片轮播示例【滑动轮播】
Jan 18 #jQuery
You might like
php多个字符串替换成同一个的解决方法
2013/06/18 PHP
PHP删除数组中特定元素的两种方法
2013/07/02 PHP
详解Window7 下开发php扩展
2015/12/31 PHP
php基于Fleaphp框架实现cvs数据导入MySQL的方法
2016/02/23 PHP
js获取浏览器基本信息大全
2014/11/27 Javascript
浅谈javascript中createElement事件
2014/12/05 Javascript
基于JavaScript实现div层跟随滚动条滑动
2016/01/12 Javascript
10个JavaScript中易犯小错误
2016/02/14 Javascript
实例讲解Jquery中隐藏hide、显示show、切换toggle的用法
2016/05/13 Javascript
Javascript之Math对象详解
2016/06/07 Javascript
jQuery事件委托之Safari
2016/07/05 Javascript
ES6所改良的javascript“缺陷”问题
2016/08/23 Javascript
对比分析Django的Q查询及AngularJS的Datatables分页插件
2017/02/07 Javascript
Angualrjs和bootstrap相结合实现数据表格table
2017/03/30 Javascript
yarn的使用与升级Node.js的方法详解
2017/06/04 Javascript
nodejs之get/post请求的几种方式小结
2017/07/26 NodeJs
javascript计算渐变颜色的实例
2017/09/22 Javascript
详解vue.js移动端配置flexible.js及注意事项
2019/04/10 Javascript
[01:08:00]Fnatic vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python基类函数的重载与调用实例分析
2015/01/12 Python
windows下ipython的安装与使用详解
2016/10/20 Python
Python中标准库OS的常用方法总结大全
2017/07/19 Python
Python运维之获取系统CPU信息的实现方法
2018/06/11 Python
详解Python解决抓取内容乱码问题(decode和encode解码)
2019/03/29 Python
Django利用cookie保存用户登录信息的简单实现方法
2019/05/27 Python
css3设置box-pack和box-align让div里面的元素垂直居中
2014/09/01 HTML / CSS
css3 flex布局 justify-content:space-between 最后一行左对齐
2020/01/02 HTML / CSS
英国男士时尚网站:Dandy Fellow
2018/02/09 全球购物
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
电台编导求职信
2014/05/06 职场文书
大学生第一学年自我鉴定2015
2014/09/28 职场文书
工程款催款函
2015/06/24 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
2015年市场营销工作总结
2015/07/23 职场文书
总经理2015中秋节致辞
2015/07/29 职场文书
寒假致家长的一封信
2015/10/10 职场文书