day 8:栈

115 阅读3分钟

“有效括号”问题

题目描述:给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足: 左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:
输入: "()"
输出: true

示例 2:
输入: "()[]{}"
输出: true

示例 3:
输入: "(]"
输出: false

示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true

思路分析:
括号成立要求就是对称性;
栈:后进先出原则---入栈和出栈顺序是对称的,比如说1、2、3、4、5、6按顺序入栈,其对应的出栈序列就是 6、5、4、3、2、1。

在遍历字符串的过程中,往栈里 push 括号对应的配对字符
注意:当判断出一对有效的括号之后,我们需要及时地丢掉它,去判断其它括号是否有效。这里这个“丢掉”的动作,就对应着两个括号一起出栈的过程。

// 用一个 map 来维护左括号和右括号的对应关系
const leftToRight = {
    "(": ")",
    "[": "]",
    "{": "}"
};

const isValid = function (s) {
    // 结合题意,空字符串无条件判断为 true
    if (!s) {
        return true;
    }
    // 初始化 stack 数组
    const stack = [];
    // 缓存字符串长度
    const len = s.length;
    // 遍历字符串
    for (let i = 0; i < len; i++) {
        // 缓存单个字符
        const ch = s[i];
        // 判断是否是左括号,这里我为了实现加速,没有用数组的 includes 方法,直接手写判断逻辑
        if (ch === "(" || ch === "{" || ch === "[") stack.push(leftToRight[ch]);
        // 若不是左括号,则必须是和栈顶的左括号相配对的右括号
        else {
            // 若栈不为空,且栈顶的左括号没有和当前字符匹配上,那么判为无效
            if (!stack.length || stack.pop() !== ch) {
                return false;
            }
        }

    }
    // 若所有的括号都能配对成功,那么最后栈应该是空的
    return !stack.length;
};

题外复习

// 且:当遇到第一个值为false时,会停止后面判断,并返回当前的当前值
// 当全部为true的时候则会默认返回最后一个值
      const firstFalse = 0 && 'a' && 2
      console.log("firstFalse:",firstFalse) // 0
      const secondFalse = 2 && null && 3
      console.log("secondFalse:",secondFalse) // null
      const thirdFalse = 2 && '1' && '' && 2
      console.log("thirdFalse:",thirdFalse) // ''
      
        const  allTrue = 3 && '23' && true && true
        console.log("allTrue:", allTrue) // 'true'
// 或:当遇到第一个为true的值则返回当前值,否则一直向后判断,如果全是false,则默认返回最后一个值
        const secondTrue = null || true || 'jajajaj'
        console.log("secondTrue:", secondTrue) // 'true'
        const AllFalse = null || '' || undefined
        console.log("AllFalse:", AllFalse) // 'undefined'

每日温度问题

题目描述: 根据每日气温列表,请重新生成一个列表输出是:后面需要再等待多少天,温度才会超过当前数值的天数。如果之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

一定要看看视频讲解

思路分析

  • 单调栈:单调递减
  • 单调栈存储是温度列表元素的下标
  • 栈为空时,直接入栈;
  • 当前温度 <= 栈顶温度(也是栈中最低温度)时,当前温度入栈;
  • 当前温度 > 栈顶温度,计算两个温度对应的下标差值(也就是我们要的新列表输出值),然后移除栈顶元素;
  • 继续遍历到当前温度 <= 栈顶温度;
  • 遍历完成,如果栈内剩余元素,那么就是没有找到比他们更高的温度下标,都输出0表示
// 入参是温度数组
const dailyTemperatures = function (T) {
    const len = T.length // 缓存数组的长度 
    const stack = [] // 初始化一个栈   
    const res = (new Array(len)).fill(0) //  初始化结果数组,注意数组定长,占位为0
    for (let i = 0; i < len; i++) {
        // 若栈不为0,且存在打破递减趋势的温度值
        while (stack.length && T[i] > T[stack[stack.length - 1]]) {
            // 将栈顶温度值对应的索引出栈
            const top = stack.pop()
            // 计算 当前栈顶温度值与第一个高于它的温度值 的索引差值
            res[top] = i - top
        }
        // 注意栈里存的不是温度值,而是索引值,这是为了后面方便计算
        stack.push(i)
    }
    // 返回结果数组
    return res
};

栈的设计——“最小栈”问题

题目描述:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2

思路分析: yeah~又是递减栈

  • 取最小值:由于整个栈从栈底到栈顶递减,因此栈顶元素就是最小元素(也就是track2栈顶是当前元素里最小的)
  • 若有新元素入栈:判断是不是比栈顶元素还要小,否则不准进入 stack2
  • 若有元素出栈:判断是不是和栈顶元素相等,如果是的话,stack2 也要出栈。
const MinStack = function () {
    this.stack = [];
    // 定义辅助栈
    this.stack2 = [];
};

MinStack.prototype.push = function (x) {
    this.stack.push(x);
    // 若入栈的值小于当前最小值,则推入辅助栈栈顶
    if (this.stack2.length == 0 || this.stack2[this.stack2.length - 1] >= x) {
        this.stack2.push(x);
    }
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function () {
    // 若出栈的值和当前最小值相等,那么辅助栈也要对栈顶元素进行出栈,确保最小值的有效性
    if (this.stack.pop() == this.stack2[this.stack2.length - 1]) {
        this.stack2.pop();
    }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function () {
    return this.stack[this.stack.length - 1];
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function () {
    // 辅助栈的栈顶,存的就是目标中的最小值
    return this.stack2[this.stack2.length - 1];
};