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 相关文章推荐
Javascript 设计模式(二) 闭包
May 26 Javascript
JS中处理与当前时间间隔的函数代码
May 23 Javascript
JS this作用域以及GET传输值过长的问题解决方法
Aug 06 Javascript
js全屏显示显示代码的三种方法
Nov 11 Javascript
JavaScript中toString()方法的使用详解
Jun 05 Javascript
JavaScript实现Fly Bird小游戏
Dec 15 Javascript
vue-router 权限控制的示例代码
Sep 21 Javascript
AngularJS日期格式化常见操作实例分析
May 17 Javascript
浅谈在react中如何实现扫码枪输入
Jul 04 Javascript
JavaScript模拟实现自由落体效果
Aug 28 Javascript
vue实现数字动态翻牌的效果(开箱即用)
Dec 08 Javascript
vue-cli设置publicPath小记
Apr 14 Javascript
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与MongoDB简介|安全|M+PHP应用实例详解
2013/06/17 PHP
ThinkPHP模板中判断volist循环的最后一条记录的验证方法
2014/07/01 PHP
用jQuery实现检测浏览器及版本的脚本代码
2008/01/22 Javascript
JavaScript实现动态增加文件域表单
2009/02/12 Javascript
javascript 异步页面查询实现代码(asp.net)
2010/05/26 Javascript
引用外部js乱码问题分析及解决方案
2013/04/12 Javascript
js函数中onmousedown和onclick的区别和联系探讨
2013/05/19 Javascript
随窗体滑动的小插件sticky源码
2013/06/21 Javascript
js读取配置文件自写
2014/02/11 Javascript
js函数调用的方式
2014/05/06 Javascript
node.js实现逐行读取文件内容的代码
2014/06/27 Javascript
深入解读JavaScript中的Iterator和for-of循环
2015/07/28 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
Javascript中for循环语句的几种写法总结对比
2017/01/23 Javascript
JavaScript html5利用FileReader实现上传功能
2020/03/27 Javascript
vue.js实现用户评论、登录、注册、及修改信息功能
2020/05/30 Javascript
详解vue 配合vue-resource调用接口获取数据
2017/06/22 Javascript
JS中touchstart事件与click事件冲突的解决方法
2018/03/12 Javascript
mpvue+vuex搭建小程序详细教程(完整步骤)
2018/09/30 Javascript
[47:08]OG vs INfamous 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
利用python程序生成word和PDF文档的方法
2017/02/14 Python
Python语言描述最大连续子序列和
2017/12/05 Python
python中ASCII码和字符的转换方法
2018/07/09 Python
Python使用pymongo模块操作MongoDB的方法示例
2018/07/20 Python
python实现本地图片转存并重命名的示例代码
2018/10/27 Python
学习Django知识点分享
2019/09/11 Python
俄罗斯和世界各地的酒店预订:Hotels.com俄罗斯
2016/08/19 全球购物
Peter Alexander新西兰站:澳大利亚领先的睡衣设计师品牌
2016/12/10 全球购物
有影响力的品牌之家:Our Social Collective
2019/06/08 全球购物
2013年入党人员的自我鉴定
2013/10/25 职场文书
个人实习生的自我评价
2014/02/16 职场文书
《高尔基和他的儿子》教学反思
2014/04/09 职场文书
竞聘上岗演讲
2014/05/19 职场文书
校庆团日活动总结
2014/08/28 职场文书
求职简历自我评价范文
2015/03/10 职场文书
少先队中队工作总结2015
2015/07/23 职场文书