栈的奇妙冒险:从括号配对到温度预言家 (LeetCode20、739)

136 阅读4分钟

一、栈:数据结构界的俄罗斯套娃

想象你有一摞盘子,每次只能拿最上面的那个,这就是栈的精髓——后进先出(LIFO) !这个简单的规则让栈成为算法界的变形金刚:

  • 叠盘子神器:新盘子压在顶部,取盘子只能从顶部开始

二、括号匹配:

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

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入: s = "()"

输出: true

示例 2:

输入: s = "()[]{}"

输出: true

示例 3:

输入: s = "(]"

输出: false

示例 4:

输入: s = "([])"

输出: true

问题场景:验证"({[]})"这样的括号串是否合法。 [20. 有效的括号 - 力扣(LeetCode)](url)

	
	var isValid = function(s) {

	  const map = { "(": ")", "[": "]", "{": "}" };

	  const stack = []; // 仓库

	 

	  for (const char of s) {

	    if (char in map) {          // 入库!

	      stack.push(char);

	    } else {                    

	      if (!stack.length) return false; 

	      const top = stack.pop();

	      if (map[top] !== char) return false; // 配对错误!

	    }

	  }

	  return !stack.length; 

	};

执行示例:

以 s = "()[]{}" 为例:

  1. ( → 入栈:stack = ['(']
  2. ) → 弹出 (obj['('] === ')' → 匹配
  3. [ → 入栈:stack = ['[']
  4. ] → 弹出 [obj['['] === ']' → 匹配
  5. { → 入栈:stack = ['{']
  6. } → 弹出 {obj['{'] === '}' → 匹配
  7. 栈空 → 返回 true 精彩看点
  • 用对象建立"左括号→右括号"的红线本
  • 左括号自觉叠高高,右括号来时检查栈顶是不是自己的真命天子
  • 最后要是还有备胎滞销,整个字符串就崩盘啦!

三、每日温度:预言家的魔法书

给定一个整数数组 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(temps) {

	  const stack = []; // 存储待解决日期的索引

	  const result = new Array(temps.length).fill(0); 

	 

	  for (let i = 0; i < temps.length; i++) {

	    // 遇到暖流,开始清算!

	    while (stack.length && temps[i] > temps[stack[stack.length-1]]) {

	      const idx = stack.pop();

	      result[idx] = i - idx; // 计算蹲守天数

	    }

	    stack.push(i); // 新温度加入监察队列

	  }

	  return result;

	};

以 temps = [73, 74, 75, 71, 69, 72, 76, 73] 为例:

当前索引 i当前温度栈 stack (索引)清算操作结果数组 result
073[0][0,0,0,0,0,0,0,0]
174[]74>73 → 弹出0, result[0]=1-0=1[1,0,0,0,0,0,0,0]
275[]75>74 → 弹出1, result[1]=2-1=1[1,1,0,0,0,0,0,0]
371[2]71<75 → 无弹出[1,1,0,0,0,0,0,0]
469[2,3]69<71 → 无弹出[1,1,0,0,0,0,0,0]
572[2]72>69 → 弹出4, result[4]=5-4=1 72>71 → 弹出3, result[3]=5-3=2[1,1,0,2,1,0,0,0]
676[]76>72 → 弹出5, result[5]=6-5=1 76>75 → 弹出2, result[2]=6-2=4[1,1,4,2,1,1,0,0]
773[6]73<76 → 无弹出[1,1,4,2,1,1,0,0]

最终结果:[1, 1, 4, 2, 1, 1, 0, 0]

算法特性

  • 时间复杂度:O(n)
    每个索引最多入栈和出栈一次,遍历一次数组。
  • 空间复杂度:O(n)
    栈的空间(最坏情况全部入栈) [739. 每日温度 - 力扣(LeetCode)](url)

魔法揭秘
1. 递减特工队:栈里藏着越来越冷的温度下标
2.触发清算:当暖流来袭时,前面的冷日子终于等到春天
3. 记忆大师:result数组记录每个寒冬的等待时长

极端天气应对

  • 连续升温:像[73,74,75,76],每个元素入栈后立即被弹出
  • 持续降温:像[76,75,74,73],所有元素保留在栈中,结果数组全为0

五、栈的核心生存哲学

这位叠罗汉大师的终极奥义,就是"后进先出俱乐部"的铁律——最后进来的家伙总是第一个被弹出去。这种特性让它在处理嵌套结构时如鱼得水:

匹配型问题:像玩多米诺骨牌,推倒一个检查一个
单调优化:用空间换时间,把O(n²)暴力算法优化成O(n)优雅舞步