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 instanceof 与typeof使用说明
Jan 11 Javascript
裁剪字符串trim()自定义改进版
Apr 10 Javascript
主页面中的两个iframe实现鼠标拖动改变其大小
Apr 16 Javascript
Node.js 学习笔记之简介、安装及配置
Mar 03 Javascript
js获取数组的最后一个元素
Apr 14 Javascript
轻量级网页遮罩层jQuery插件用法实例
Jul 31 Javascript
javascript中window.open在原来的窗口中打开新的窗口(不同名)
Nov 15 Javascript
Bootstrap页面标题Page Header的实现方法
Mar 22 Javascript
JavaScript实现自动跳转文本功能
May 25 Javascript
React Native 通告消息竖向轮播组件的封装
Aug 25 Javascript
原生JavaScript之es6中Class的用法分析
Feb 23 Javascript
three.js 将图片马赛克化的示例代码
Jul 31 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
解析zend studio中直接导入svn中的项目的方法步骤
2013/06/21 PHP
PHP中把对象数组转换成普通数组的方法
2015/07/10 PHP
PHP中echo与print区别点整理
2021/03/09 PHP
javascript 二进制运算技巧解析
2012/11/27 Javascript
jquery限制输入字数,并提示剩余字数实现代码
2012/12/24 Javascript
JS控制文本框textarea输入字数限制的方法
2013/06/17 Javascript
解析页面加载与js函数的执行 onload or ready
2013/12/12 Javascript
DOM节点删除函数removeChild()用法实例
2015/01/12 Javascript
javascript格式化json显示实例分析
2015/04/21 Javascript
JavaScript实现删除,移动和复制文件的方法
2015/08/05 Javascript
JS实现可自定义大小,可双击关闭的弹出层效果
2015/10/16 Javascript
利用JS实现数字增长
2016/07/28 Javascript
常用js,css文件统一加载方法(推荐) 并在加载之后调用回调函数
2016/09/23 Javascript
javascript 产生随机数的几种方法总结
2017/09/26 Javascript
Vue中对比scoped css和css module的区别
2018/05/17 Javascript
vue-cli 打包使用history模式的后端配置实例
2018/09/20 Javascript
小程序实现新用户判断并跳转激活的方法
2019/05/20 Javascript
vue中touch和click共存的解决方式
2020/07/28 Javascript
详解ES6 中的Object.assign()的用法实例代码
2021/01/11 Javascript
使用pyecharts在jupyter notebook上绘图
2020/04/23 Python
python生成随机图形验证码详解
2017/11/08 Python
python获取地震信息 微信实时推送
2019/06/18 Python
django 中QuerySet特性功能详解
2019/07/25 Python
Python 实现判断图片格式并转换,将转换的图像存到生成的文件夹中
2020/01/13 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
2020/03/02 Python
python 深度学习中的4种激活函数
2020/09/18 Python
日本一家专门经营各种箱包的大型网站:Traveler Store
2016/08/03 全球购物
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
Yves Rocher捷克官方网站:植物化妆品的创造者
2019/07/31 全球购物
Puma印度官网:德国运动品牌
2019/10/06 全球购物
限量版运动鞋和街头服饰:TheDrop
2020/09/06 全球购物
C语言变量的命名规则都有哪些
2013/12/27 面试题
阿里巴巴的Oracle DBA笔试题答案-SQL tuning类
2016/04/03 面试题
中专自我鉴定范文
2013/10/16 职场文书
求职信的最佳写作思路
2014/02/01 职场文书
创业分两种人:那么哪些适合创业?,哪些适合不适合创业呢?
2019/08/23 职场文书