JavaScript數(shù)據(jù)結(jié)構(gòu)之棧實(shí)例用法
棧
先來看一道題
Leetcode 32 Longest Valid Parentheses (最長(zhǎng)有效括號(hào))
給定一個(gè)只包含 '(' 和 ')' 的字符串,找出最長(zhǎng)的包含有效括號(hào)的子串的長(zhǎng)度。
示例 1:
輸入: "(()"
輸出: 2
解釋: 最長(zhǎng)有效括號(hào)子串為 "()"
示例 2:
輸入: ")()())"
輸出: 4
解釋: 最長(zhǎng)有效括號(hào)子串為 "()()"
這道題可以用動(dòng)態(tài)規(guī)劃來做,也能用簡(jiǎn)潔明了的棧來解決。
什么是棧?
棧是一種先進(jìn)后出(LIFO)的有序集合,新添加的元素在棧頂,舊元素在棧底。
以下圖為例,1、2、3、4、5、6、7先后進(jìn)棧:

創(chuàng)建棧
創(chuàng)建一個(gè)類來表示棧:
class Stack {
// 初始化類,創(chuàng)建數(shù)組 items 存放入棧元素
constructor() {
this.items = [];
}
// push 方法進(jìn)行元素入棧(可同時(shí)入棧一或多個(gè)元素),無返回值
push() {
this.items.push(...arguments);
}
// pop 方法出棧一個(gè)元素,返回出棧元素
pop() {
return this.items.pop();
}
// peek 方法返回棧頂元素,不對(duì)棧本身做任何操作
peek() {
return this.items[this.items.length-1];
}
// size 方法返回棧內(nèi)元素個(gè)數(shù)
size() {
return this.items.length;
}
// isEmpty 方法查看棧是否為空,返回布爾值
isEmpty() {
return this.items.length == 0;
}
// clear 方法清空棧,無返回值
clear() {
this.items = [];
}
// print 方法打印棧內(nèi)元素
print() {
console.log(this.items.toString());
}
}
// 測(cè)試
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();
注意
因?yàn)?JavaScript 的類內(nèi)暫時(shí)無法定義私有成員,所以可以在類外訪問到存儲(chǔ)棧元素的數(shù)組 items,這個(gè)操作是很危險(xiǎn)的。
stack.items; // [1, 2, 3, 4]
這時(shí)可以使用閉包和IIFE進(jìn)行避免,這是一個(gè)很無奈的辦法:
let Stack = (function () {
// 使用 WeakMap 存儲(chǔ)數(shù)組(數(shù)組存放進(jìn)棧元素)
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的鍵值對(duì)集合,但WeakMap的鍵是弱引用的,只要不存在引用,垃圾回收機(jī)制就會(huì)回收掉占用的內(nèi)存,相當(dāng)于自動(dòng)刪除,而不用手動(dòng)刪除。
用棧解題
思路:
變量start存放有效括號(hào)起始下標(biāo),maxLen存放最大長(zhǎng)度;
棧只存放左括號(hào)的下標(biāo),遇到左括號(hào),將其下標(biāo)存入棧中;
遇到右括號(hào),若此時(shí)棧為空,跳過本次循環(huán)并更新start;若棧不為空,則棧頂元素出棧;
棧頂元素出棧后,若棧為空,則計(jì)算當(dāng)前下標(biāo)和start的距離,并更新maxLen;
棧頂元素出棧后,若棧不為空,則計(jì)算當(dāng)前下標(biāo)和棧頂存放的下標(biāo)的距離,并更新maxLen;
循環(huán)遍歷直至結(jié)束。
function test(str) {
let stack = new Stack();
let start = 0;
let maxLen = 0;
for(let i=0; i<str.length; i++) {
// 如果是左括號(hào),下標(biāo)入棧
if (str[i] == '(') {
stack.push(i);
} else {
// 如果是右括號(hào)
/* 棧內(nèi)為空,說明本次有效括號(hào)匹配已結(jié)束,跳過本次循環(huán)并更新 start */
if (stack.isEmpty()) {
start = i+1;
continue;
} else {
// 棧內(nèi)不為空,則出棧一個(gè)左括號(hào)進(jìn)行匹配
stack.pop();
// 棧頂元素出棧后,棧為空
if (stack.isEmpty()) {
// 根據(jù)當(dāng)前下標(biāo)和 start 去更新 maxLen
maxLen = Math.max(maxLen, i-start+1);
} else {
// 棧不為空,根據(jù)當(dāng)前下標(biāo)和棧頂存放的下標(biāo)去更新 maxLen
maxLen = Math.max(maxLen, i-stack.peek());
}
}
}
}
return maxLen;
}
test('(()'); // 2
test(')()())'); // 4
相關(guān)文章
微信小程序js文件改變參數(shù)并在視圖上及時(shí)更新【推薦】
這篇文章主要介紹了微信小程序js文件改變參數(shù)并在視圖上及時(shí)更新的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-06-06
IE6/7中g(shù)etAttribute獲取href/src 屬性(相對(duì)路徑0值與其它瀏覽器不同
IE6/7中g(shù)etAttribute獲取href/src 屬性(相對(duì)路徑0值與其它瀏覽器不同的解決方法2011-08-08
JS簡(jiǎn)單編號(hào)生成器實(shí)現(xiàn)方法(附demo源碼下載)
這篇文章主要介紹了JS簡(jiǎn)單編號(hào)生成器實(shí)現(xiàn)方法,涉及JavaScript針對(duì)表單與字符串操作的相關(guān)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-04-04
Underscore之Array_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Underscore之Array的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Typescript中使用引用路徑別名報(bào)錯(cuò)的解決方法
本文主要介紹了Typescript中使用引用路徑別名報(bào)錯(cuò)的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
利用chrome瀏覽器進(jìn)行js調(diào)試并找出元素綁定的點(diǎn)擊事件詳解
“工欲善其事,必先利其器” 恩,這句話我覺得說的特別有道理,下面這篇文章主要給大家介紹了關(guān)于利用chrome瀏覽器進(jìn)行js調(diào)試并找出元素綁定的點(diǎn)擊事件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-09-09
js+canvas實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲
這篇文章主要為大家詳細(xì)介紹了js+canvas實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02

