如何利用栈完成方向字符串的自动对消简化

作者:袖梨 2026-06-29

本文详解使用栈结构消除相反方向(如NORTH/SOUTH、EAST/WEST)的算法原理,重点解析stack[stack.length - 1]的安全访问逻辑、空栈边界行为,以及为何不会因读取未定义值导致错误。

本文详解使用栈结构消除相反方向(如north/south、east/west)的算法原理,重点解析`stack[stack.length - 1]`的安全访问逻辑、空栈边界行为,以及为何不会因读取未定义值导致错误。

该函数 dirReduc 的核心思想是:利用栈的“后进先出”特性,实时匹配并抵消相邻的相反方向。例如,['NORTH', 'SOUTH'] 应被完全移除;而 ['NORTH', 'EAST', 'SOUTH'] 中,NORTH 与 SOUTH 不相邻,故不抵消——但本算法通过栈动态维护“尚未被抵消的方向序列”,使非相邻但可间接抵消的方向也能被处理(如 ['NORTH', 'SOUTH', 'SOUTH'] → 先抵消前两个,留下 ['SOUTH'])。

关键点在于对 stack[stack.length - 1] 的访问:

  • 当 stack 为空时,stack.length 为 0,因此 stack[stack.length - 1] 等价于 stack[-1] —— JavaScript 中这是合法语法,返回 undefined,而非报错
  • 在条件判断中,undefined === 'NORTH' 等所有比较结果均为 false,因此整个 if 条件不成立,流程自然进入 else 分支,将当前方向 push 入栈。
  • 换言之:空栈时的 stack[stack.length - 1] 安全且可控,它保证了首次循环必走 push 路径,从而让栈逐步“建立起来”

下面是一个带调试注释的增强版实现:

function dirReduc(arr) {  const stack = [];  for (let direction of arr) {    const last = stack[stack.length - 1]; // 可能为 undefined(空栈时)    // 只有当栈非空且方向相反时才抵消    const isOpposite =      (direction === 'NORTH' && last === 'SOUTH') ||      (direction === 'SOUTH' && last === 'NORTH') ||      (direction === 'EAST'  && last === 'WEST')  ||      (direction === 'WEST'  && last === 'EAST');    if (isOpposite) {      stack.pop(); // 抵消:移除栈顶      console.log(`抵消: ${last} ←→ ${direction}, 栈变为 [${stack.join(', ')}]`);    } else {      stack.push(direction); // 累积:入栈      console.log(`入栈: ${direction}, 栈变为 [${stack.join(', ')}]`);    }  }  return stack;}// 示例调用console.log(dirReduc(['NORTH', 'SOUTH', 'EAST', 'WEST'])); // → []console.log(dirReduc(['NORTH', 'SOUTH', 'SOUTH', 'EAST', 'WEST', 'WEST'])); // → ['SOUTH', 'WEST']

⚠️ 注意事项:

  • 该算法仅处理直接相反的两两方向,不支持斜向(如 'NORTHEAST')或自定义映射;
  • 时间复杂度为 O(n),空间复杂度最坏 O(n)(无任何抵消时);
  • 若输入含非法方向(如 'UP'),它会被无条件入栈——建议在生产环境增加校验;
  • stack[stack.length - 1] 是惯用写法,等价于 stack.at(-1)(ES2022+),后者语义更清晰,但兼容性略低。

总结:栈在此处扮演“待决方向缓冲区”的角色;stack[stack.length - 1] 的巧妙之处,在于它天然兼容空栈场景,无需额外 if (stack.length > 0) 判断——这正是函数简洁而健壮的关键设计。

相关文章

精彩推荐