本文开头先来介绍下栈这个数据结构
栈结构
后面进来的会先出去 也就是后进先出
只能在栈顶操作 push pop
常见栈结构 比如函数调用栈。游览器的历史记录
实现一个栈结构
class Stack{
_item = [];
push(val){
this._item.push(val)
}
pop(){
return this._item.pop()
}
peek(){
return this._item.at(-1)
}
isEmpty(){
return this._item.length === 0
}
size(){
return this._item.length
}
clear(){
this._item = []
}
toString(){
return this._item.join("")
}
}
最小栈
设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack
类:
MinStack()
初始化堆栈对象。void push(int val)
将元素val推入堆栈。void pop()
删除堆栈顶部的元素。int top()
获取堆栈顶部的元素。int getMin()
获取堆栈中的最小元素。
var MinStack = function() {
// 关键问题,如何维护栈中的最小元素?注意,是常数级别找到,也就是保存数组的index 还是直接存储值?
this.stack = [];
this.minVal = undefined;
};
/**
* @param {number} val
* @return {void}
*/
MinStack.prototype.push = function(val) {
this.stack.push(val);
if (this.minVal === undefined) {
this.minVal = val;
} else {
this.minVal = Math.min(val, this.minVal);
}
};
/**
* @return {void}
*/
MinStack.prototype.pop = function() {
const val = this.stack.pop();
if (val === this.minVal) { // 如果是栈最小元素出去了,再次寻找最小值
this.minVal = this.stack[0];
for (let i = 1; i < this.stack.length; i++) {
this.minVal = Math.min(this.stack[i], this.minVal);
}
}
return val;
};
/**
* @return {number}
*/
MinStack.prototype.top = function() {
if (this.stack.length === 0) {
return null;
}
return this.stack[this.stack.length - 1];
};
/**
* @return {number}
*/
MinStack.prototype.getMin = function() {
return this.minVal;
};
字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string]
,表示其中方括号内部的 encoded_string
正好重复 k
次。注意 k
保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k
,例如不会出现像 3a
或 2[4]
的输入。
示例 1:
**输入:**s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
**输入:**s = “3[a2[c]]”
输出:“accaccacc”
示例 3:
**输入:**s = “2[abc]3[cd]ef”
输出:“abcabccdcdcdef”
示例 4:
**输入:**s = “abc3[cd]xyz”
输出:“abccdcdcdxyz”
思路:遍历输入的编码字符串:
如果遇到数字,则更新倍数;
如果遇到左括号 [
,则将当前倍数和已经解码的字符串入栈,并分别清零;
如果遇到右括号 ]
,则弹出倍数栈和字符串栈,进行解码并更新当前字符串;
如果遇到字母,则更新当前字符串。
var decodeString = function(s) {
let stack = [];
let curNum = 0;
let curStr = '';
for (let char of s) {
if (char === '[') {
stack.push(curStr);
stack.push(curNum);
curStr = '';
curNum = 0;
} else if (char === ']') {
let num = stack.pop();
let prevStr = stack.pop();
curStr = prevStr + curStr.repeat(num);
} else if (char >= '0' && char <= '9') {
curNum = curNum * 10 + parseInt(char);
} else {
curStr += char;
}
}
return curStr;
};
每日温度
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
思路:遍历温度数组,对于每一天的温度,如果栈不为空且当前温度高于栈顶元素对应的温度,那么就可以计算出栈顶元素对应的下一天更高温度出现的时间(即当前索引减去栈顶元素索引),并继续处理栈中其他元素,直到栈为空或栈顶元素对应的温度不再比当前温度低。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
思路
var dailyTemperatures = function(temperatures) {
const result = new Array(temperatures.length).fill(0); // 初始化结果数组,全部填充为0
const stack = []; // 创建一个栈,用于存储温度数组索引
for (let i = 0; i < temperatures.length; i++) {
// 当栈不为空且当前温度高于栈顶元素对应的温度时
while (stack.length > 0 && temperatures[i] > temperatures[stack[stack.length - 1]]) {
// 弹出栈顶元素,并计算等待天数
const index = stack.pop();
result[index] = i - index;
}
// 将当前温度索引压入栈中
stack.push(i);
}
return result;
};