前言
今天我们来打打基础,学习栈的数据结构并通过例题来使用栈。
栈有的功能数组都有,所以在学习栈之前我们先来复习一下数据的几个知识点。
正文
数组复习
fill()填充数组
先初始化一个数组
const arr = new Array(8)
console.log(arr);
创建一个具有指定长度的空数组。
这个数组的初始长度是8,但是并没有任何元素被初始化。
所以数组的每个位置都是 undefined。
使用 fill 方法将数组的每个元素都设置为数字8。
const arr = new Array(8).fill(8)
console.log(arr);
foreEcah遍历数组
const arr = new Array(4).fill(9)
arr.forEach(function (item, index, arr) {
console.log(item, index, arr);
});
item:当前数组元素的值。index:当前元素在数组中的索引位置。arr:整个数组的引用,即forEach方法正在遍历的那个数组。
输出:
map()对数组的每个值进行操作
map和forEach都能遍历数组,但的不同点在于map有返回值,可对数组的值进行操作。
map 不会改变原始数组,而是返回一个新的数组。
const arr = new Array(4).fill(9)
const newArr = arr.map(function (item, index, arr) {
console.log(item, index, arr);
return item + 1
});
console.log(newArr);
二维数组
二维数组是一种数组的数据结构,里面的元素也是数组,因此可以将其视为“数组的数组
const arr = [// 二维数组 arr
[1, 2, 3, 4, 5],
[11, 22, 33, 44, 55],
[10, 20, 30, 40, 50],
[100, 200, 300, 400, 500],
];
// 遍历二维数组 arr 的每一行
for (let i = 0; i < arr.length; i++) {
// 获取当前行,即 arr 的第 i 个子数组
const itemArr = arr[i];
// 开始遍历当前行(itemArr)的每一个元素
for (let j = 0; j < itemArr.length; j++) {
// 将当前元素(itemArr 的第 j 个元素)转换为字符串
itemArr[j] = String(itemArr[j]);
}
}
// 打印修改后的二维数组 arr,此时 arr 中的所有元素均为字符串类型
console.log(arr);
数组的其他方法
const arr = [1, 2]
arr.push(3)//尾部增加(会直接修改原来数组)
arr.unshift(0)//头部增加
console.log(arr);
arr.pop()//移除尾部
arr.shift()//移除头部
console.log(arr);
// 数组中增加元素 第一参数是位置,第二个是要删几个 第三个参数是插入的元素
arr.splice(1, 0, 'hello')
console.log(arr);
arr.splice(1, 1)
console.log(arr);
栈
栈(Stack)是一种线性数据结构,其特点是后进先出(Last In First Out,简称LIFO)。栈是一个只能使用push和pop的数组,可以理解为是阉割版数组。
栈的基本操作
- push: 向栈顶添加一个元素。
- pop: 移除栈顶的元素并返回它。
- peek/top: 查看栈顶的元素,但不移除它。
- isEmpty: 检查栈是否为空。
- size: 返回栈中元素的数量
例题
有效的括号
题目地址: leetcode.cn/problems/va…
这题我们采用的思路是:
存进括号的另一半,如果字符串是“({}[])”那么我们就存“)}{][(”,
var isValid = function(s) {
//如果字符串的长度是奇数,那么它不可能是有效的括号串
if(s.length%2==1){
return false
}
//存储左括号到右括号的映射关系
const leftToRight ={
'(':')',
'[':']',
'{':'}' }
//存储待匹配的右括号
const stack =[]
for(var i =0 ;i<s.length;i++){
// 如果当前字符是左括号,找到对应的右括号将其压入栈中。
if(s[i]=='('||s[i]=='['||s[i]=='{'){
//将它对应的另一半入栈
let self =s[i] stack.push(leftToRight[self])
}else{
//如果当前字符是右括号,从栈顶弹出一个元素,如果栈顶元素与当前右括号不匹配,则说明括号序列无效
let r = s[i] let top = stack.pop()
if(r!==top){
return false
}
}
}
//检查栈是否为空,如果是有效括号,栈里必然为空,都对应完了
return !stack.length
};
最小栈
这题的重点在于如何在尽量降低时间复杂度以获取堆栈中的最小元素。
题目给的要求是O(1),采用常规的for循环查找最小值其实也能过,因为题目中给的测试样例没有特别特别长的:
时间复杂度为O(n):
var MinStack = function () {
this.stack = [];
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function (x) {
this.stack.push(x);
};
/**
* @return {void}
*/
MinStack.prototype.pop = function () {
this.stack.pop();
};
/**
* @return {number}
*/
MinStack.prototype.top = function () {
return this.stack[this.stack.length - 1];
};
/**
* @return {number}
*/
MinStack.prototype.getMin = function () {
let min = Number.MAX_SAFE_INTEGER;
for (const item of this.stack) {
if (item < min) {
min = item;
}
}
return min;
};
时间复杂度为O(1)的思路是:
使用两个栈,stack用来存放原始值,
另一个栈min_stack 的顶部元素始终反映着 stack 中的最小值,从而实现了 O(1) 时间复杂度的最小值查询。
var MinStack = function () {
this.stack = [];
//辅助栈,存储当前 stack 中的最小值
//初始化为 [Infinity] 是为了保证任何首次 push 的元素都会小于这个初始值
this.min_stack = [Infinity];//Infinity 是 JavaScript 中的一个特殊数值,表示正无穷大
};
/**
* @param {number} x
* @return {void}
*/
MinStack.prototype.push = function (x) {
this.stack.push(x);
//计算最小值,保证了顶部总是栈中的当前最小值。
this.min_stack.push(Math.min(this.min_stack[this.min_stack.length - 1], x));
};
/**
* @return {void}
*/
MinStack.prototype.pop = function () {
this.stack.pop();
//把辅助栈的最小值也出栈
this.min_stack.pop();
};
/**
* @return {number}
*/
MinStack.prototype.top = function () {
return this.stack[this.stack.length - 1];
};
/**
* @return {number}
*/
MinStack.prototype.getMin = function () {
return this.min_stack[this.min_stack.length - 1];
};
结语
以上就是本文的全部内容,主要回顾了数组的基本方法和学习了栈的使用,希望本文对你有所帮助,感谢你的阅读!