TypeScript數(shù)據(jù)結構棧結構Stack教程示例
1. 認識棧結構
棧是一種 后進先出(LIFO) 的數(shù)據(jù)結構
在 js 中沒有棧,但我們可以用 數(shù)組或鏈表 實現(xiàn)棧的所有功能
棧的常用操作:
push(入棧)
pop(出棧)
peek(返回棧頂元素)
isEmpty(判斷是否為空棧)
size(返回棧里元素個數(shù))
棧的結構示意圖

2. 實現(xiàn)棧結構的封裝
實現(xiàn)棧結構有兩種比較常見的方式:
- 基于 數(shù)組 實現(xiàn)
- 基于 鏈表 實現(xiàn)
鏈表也是一種數(shù)據(jù)結構,js 中沒有自帶鏈表結構,后續(xù)會寫關于鏈表的文章,本章先使用數(shù)組來實現(xiàn)。
2.1 基于數(shù)組 v1 版
// 封裝一個棧
class ArrayStack {
// 定義一個數(shù)組,用于存儲元素
private data: any[] = [];
constructor(data: any[]) {
this.data = data || [];
}
// 實現(xiàn)棧中相關的操作方法
// push 方法:將一個元素壓入棧中
push(element: any): void {
this.data.push(element);
}
// pop方法:將棧頂?shù)脑貜棾鰲#ǚ祷爻鋈?,并且從棧頂移除?
pop(): any {
return this.data.pop();
}
// peek方法:返回棧頂元素
peek(): any {
return this.data[this.data.length - 1];
}
// isEmpty方法:判斷棧是否為空
isEmpty(): boolean {
return this.data.length === 0;
}
// size放法:返回棧里元素個數(shù)
size(): number {
return this.data.length;
}
}
測試:
const as = new ArrayStack();
as.push(1);
as.push(2);
as.pop();
as.push(3);
console.log(as); // ArrayStack { data: [ 1, 3 ] }
2.2 使用泛型重構 v2 版
上面我們已經(jīng)基于數(shù)組實現(xiàn)了一個棧結構,其實是已經(jīng)可以使用了。
但是有個小問題就是并不能很好的限制棧中元素的類型,原因就是我們用了太多 any,這種情況下我們可以使用范型來限制
// 封裝一個棧
class ArrayStack<T = any> {
// 定義一個數(shù)組,用于存儲元素
private data: T[] = [];
constructor(data: T[]) {
this.data = data || [];
}
// 實現(xiàn)棧中相關的操作方法
// push 方法:將一個元素壓入棧中
push(element: T): void {
this.data.push(element);
}
// pop方法:將棧頂?shù)脑貜棾鰲#ǚ祷爻鋈?,并且從棧頂移除?
pop(): T | undefined {
return this.data.pop();
}
// peek方法:返回棧頂元素
peek(): T | undefined {
return this.data[this.data.length - 1];
}
// isEmpty方法:判斷棧是否為空
isEmpty(): boolean {
return this.data.length === 0;
}
// size放法:返回棧里元素個數(shù)
size(): number {
return this.data.length;
}
}
測試:
const as = new ArrayStack<number>();
as.push(1);
as.push('2'); // ?? 類型“string”的參數(shù)不能賦給類型“number”的參數(shù)。
as.push(2);
as.pop();
as.push(3);
console.log(as);
3. 實戰(zhàn)一:有效的括號
這道題來自 Leetcode 上的第 20 道題,難度:簡單
3.1 題目描述
給定一個只包括 '(',')','{','}','[',']' 的字符串 s ,判斷字符串是否有效。
有效字符串需滿足:
- 左括號必須用相同類型的右括號閉合。
- 左括號必須以正確的順序閉合。
- 每個右括號都有一個對應的相同類型的左括號。
示例 1:
輸入: s = "()"
輸出: true
示例 2:
輸入: s = "()[]{}"
輸出: true
示例 3:
輸入: s = "(]"
輸出: false
提示:
1 <= s.length <= 104s僅由括號'()[]{}'組成
3.2 題目分析
這是一道非常經(jīng)典的關于 棧 的面試題
我們只需要維護一個棧結構
遍歷給定的字符串 s:
遇到 [、{、( 這三種符號時將它們壓入棧,
遇到 ]、}、) 這三種符號時就取出棧頂元素與之對比,如果不能夠組成有效括號則函數(shù)直接返回 false,如果能則進入下個循環(huán)比較
知道循環(huán)結束,判斷棧中元素如果為空則表示字符串有效,反之則無效
3.3 解一:棧
function isValid(s: string): boolean {
const stack = new ArrayStack<string>();
for (let i = 0; i < s.length; i++) {
const c = s[i];
switch (c) {
case "{":
stack.push("}");
break;
case "[":
stack.push("]");
break;
case "(":
stack.push(")");
break;
default:
if (stack.pop() !== c) return false;
}
}
return stack.isEmpty();
}
4. 實戰(zhàn)二:下一個更大元素 I
這道題是來自 Leetcode 上的第 496 道題,難度:簡單
4.1 題目描述
nums1 中數(shù)字 x 的 下一個更大元素 是指 x 在 nums2 中對應位置 右側(cè) 的 第一個 比 x ****大的元素。
給你兩個 沒有重復元素 的數(shù)組 nums1 和 nums2 ,下標從 0 開始計數(shù),其中nums1 是 nums2 的子集。
對于每個 0 <= i < nums1.length ,找出滿足 nums1[i] == nums2[j] 的下標 j ,并且在 nums2 確定 nums2[j] 的 下一個更大元素 。如果不存在下一個更大元素,那么本次查詢的答案是 -1 。
返回一個長度為 nums1.length 的數(shù)組 **ans **作為答案,滿足 **ans[i] **是如上所述的 下一個更大元素 。
示例 1:
輸入: nums1 = [4,1,2], nums2 = [1,3,4,2].
輸出: [-1,3,-1]
解釋: nums1 中每個值的下一個更大元素如下所述:
- 4 ,用加粗斜體標識,nums2 = [1,3,4,2]。不存在下一個更大元素,所以答案是 -1 。
- 1 ,用加粗斜體標識,nums2 = [1,3,4,2]。下一個更大元素是 3 。
- 2 ,用加粗斜體標識,nums2 = [1,3,4,2]。不存在下一個更大元素,所以答案是 -1 。
示例 2:
輸入: nums1 = [2,4], nums2 = [1,2,3,4].
輸出: [3,-1]
解釋: nums1 中每個值的下一個更大元素如下所述:
- 2 ,用加粗斜體標識,nums2 = [1,2,3,4]。下一個更大元素是 3 。
- 4 ,用加粗斜體標識,nums2 = [1,2,3,4]。不存在下一個更大元素,所以答案是 -1 。
提示:
1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 104
nums1和nums2中所有整數(shù) 互不相同
nums1 中的所有整數(shù)同樣出現(xiàn)在 nums2 中
4.2 解一:暴力
這道題可以通過暴力法解決。
思路:
- 雙重循環(huán)遍歷
nums1和nums2兩個數(shù)組 - 在第一層遍歷
nums1循環(huán)中,找出nums1[i]對應 在nums2中的下標位置pos - 從
pos + 1位置開始遍歷 nums2 數(shù)組,查找比nums[i]大的數(shù)字
代碼:
function nextGreaterElement(nums1: number[], nums2: number[]): number[] {
let res: number[] = [];
for (let i = 0; i < nums1.length; i++) {
let pos: number = 0;
for (let j = 0; j < nums2.length; j++) {
if (nums2[j] === nums1[i]) {
pos = j;
break;
}
}
if (pos === nums2.length - 1) res.push(-1);
for (let j = pos + 1; j < nums2.length; j++) {
if (nums2[j] > nums1[i]) {
res.push(nums2[j]);
break;
}
if (j >= nums2.length - 1) res.push(-1);
}
}
return res;
}
復雜度分析
時間復雜度:O(mn) ,其中 m 是 nums1 的長度,n 是 nums2 的長度。
空間復雜度:O(1)
4.3 解二:單調(diào)棧
當題目出現(xiàn)「找到最近一個比其大的元素」的字眼時,應該要會想到「單調(diào)?!?。
解釋一下什么是單調(diào)棧:就是棧中存放的數(shù)據(jù)是有序的,比如:單調(diào)遞增棧 和 單調(diào)遞減棧
思路:
- 創(chuàng)建一個
map(哈希表),它的key為nums2中的值,value為key值右側(cè)的 下一個更大元素 - 維護一個
stack單調(diào)棧,倒序遍歷nums2數(shù)組 - 在循環(huán)中比較
nums2[i]與 單調(diào)棧中的值,將小于nums2[i]的值pop出,最后剩下的都是比nums2[i]大的數(shù),且棧頂?shù)闹稻褪窍乱粋€更大元素 - 使用
map哈希表記錄每個nums2[i]對應目標值。
function nextGreaterElement(nums1: number[], nums2: number[]): number[] {
const map = new Map<number, number>();
const stack = new ArrayStack<number>();
for (let i = nums2.length - 1; i >= 0; --i) {
const num = nums2[i];
while (stack.size() && num >= (stack.peek() as number)) {
stack.pop();
}
map.set(num, stack.size() ? (stack.peek() as number) : -1);
stack.push(num);
}
const res = new Array(nums1.length).fill(0).map((_, i) => map.get(nums1[i]) as number);
return res;
}
復雜度分析
時間復雜度:O(m + n) ,其中 m 是 nums1 的長度,n 是 nums2 的長度。
空間復雜度:O(n) 用于存儲哈希表 map
以上就是TypeScript數(shù)據(jù)結構棧結構Stack教程示例的詳細內(nèi)容,更多關于TypeScript數(shù)據(jù)結構Stack的資料請關注腳本之家其它相關文章!
相關文章
xterm.js在web端實現(xiàn)Terminal示例詳解
這篇文章主要為大家介紹了xterm.js在web端實現(xiàn)Terminal示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
TypeScript Module Resolution解析過程
這篇文章主要為大家介紹了TypeScript Module Resolution解析過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
Typescript?轉(zhuǎn)換類型操作索引映射類型IIMT模式學習
這篇文章主要為大家介紹了Typescript?轉(zhuǎn)換類型操作之索引映射類型IIMT模式學習,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07

