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 相关文章推荐
location.search在客户端获取Url参数的方法
Jun 08 Javascript
jQuery的Ajax的自动完成功能控件简要说明
Feb 22 Javascript
js中return false(阻止)的用法
Aug 14 Javascript
2014年50个程序员最适用的免费JQuery插件
Dec 15 Javascript
异步安全加载javascript文件的方法
Jul 21 Javascript
jQuery实现的网页右下角tab样式在线客服效果代码
Oct 23 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之绑定事件
Nov 19 Javascript
深入分析jQuery的ready函数是如何工作的(工作原理)
Dec 17 Javascript
有关文件上传 非ajax提交 得到后台数据问题
Oct 12 Javascript
详解组件库的webpack构建速度优化
Jun 18 Javascript
菊花转动的jquery加载动画效果
Aug 19 jQuery
详解ES6 CLASS在微信小程序中的应用实例
Apr 24 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面向对象全攻略 (四)构造方法与析构方法
2009/09/30 PHP
php生成图形验证码几种方法小结
2013/08/15 PHP
php过滤敏感词的示例
2014/03/31 PHP
将二维数组转为一维数组的2种方法
2014/05/26 PHP
神盾加密解密教程(二)PHP 神盾解密
2014/06/08 PHP
PHP生成不重复随机数的方法汇总
2014/11/19 PHP
PHP实现生成唯一会员卡号
2015/08/24 PHP
PHP json_encode() 函数详解及中文乱码问题
2015/11/05 PHP
Laravel 5使用Laravel Excel实现Excel/CSV文件导入导出的功能详解
2017/10/11 PHP
项目实践之javascript技巧
2007/12/06 Javascript
浅谈被jQuery抛弃的函数及替代函数
2015/05/03 Javascript
JQuery datepicker 用法详解
2015/12/25 Javascript
JavaScript中用let语句声明作用域的用法讲解
2016/05/20 Javascript
jquery siblings获取同辈元素用法实例分析
2016/07/25 Javascript
Angular2中select用法之设置默认值与事件详解
2017/05/07 Javascript
老生常谈ES6中的类
2017/07/31 Javascript
认识jQuery的Promise的具体使用方法
2017/10/10 jQuery
React全家桶环境搭建过程详解
2018/05/18 Javascript
微信小程序实现城市列表选择
2018/06/05 Javascript
通过循环优化 JavaScript 程序
2019/06/24 Javascript
JS为什么说async/await是generator的语法糖详解
2019/07/11 Javascript
wx-charts 微信小程序图表插件的具体使用
2019/08/18 Javascript
[00:59]DOTA2背景故事第二期之四大基本法则
2020/07/07 DOTA
在Python的Django框架中获取单个对象数据的简单方法
2015/07/17 Python
python根据京东商品url获取产品价格
2015/08/09 Python
python实现文本进度条 程序进度条 加载进度条 单行刷新功能
2019/07/03 Python
美国女鞋品牌:naturalizer(娜然)
2016/08/01 全球购物
采用专利算法搜索最廉价的机票:CheapAir
2016/09/10 全球购物
在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern "C"
2014/08/09 面试题
公司活动总结范文
2014/07/01 职场文书
放飞梦想演讲稿800字
2014/08/26 职场文书
群众路线教育实践活动总结
2014/10/30 职场文书
2015年城市管理工作总结
2015/05/23 职场文书
污染环境建议书
2015/09/14 职场文书
Java 将PPT幻灯片转为HTML文件的实现思路
2021/06/11 Java/Android
深入理解go缓存库freecache的使用
2022/02/15 Golang