算法-栈

144 阅读3分钟

最小栈

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

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

思路

  • 在JS中使用数组模拟栈
  • 在新增/移除元素到栈中时,需要重新计算最小值

代码实现

/**
 * @param  {number}  val
 * @return  {void}
 */
class  MinStack {
  constructor() {
    this.list = []
    // 开始赋值为无限大值Infinity
    this.minStack = Infinity
  }
  push(val) {
    this.list.push(val)
    this.computedMin()
  }
  // 计算最小值
  computedMin() {
    this.min = Math.min(...this.list)
  }
  pop() {
    const  result = this.list.pop()
    this.computedMin()
    return  result
  }
  top() {
    return  this.list[this.list.length - 1]
  }
  getMin() {
    return  this.min
  }
}

删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

  • 示例:
输入:"abbaca"
输出:"ca"

解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"

思路

  • 遍历字符串,逐个入栈,
  • 入栈时,取出栈顶元素,判断当前字符串与栈顶元素是否相等
  • 如果不相等,栈顶元素再次入栈,新元素入栈
/**
 * @param {string} s
 * @return {string}
 */
const removeDuplicates = function (s) {
  const stack = []
  for (const str of s) {
    const result = stack.pop()
    if (result !== str) {
      stack.push(result)
      stack.push(str)
    }
  }
  return stack.join('')
}

删除字符串中的所有相邻重复项 II

给你一个字符串s,「k 倍重复项删除操作」将会从s中选择k个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。

你需要对s重复进行无限次这样的删除操作,直到无法继续为止。

在执行完所有删除操作后,返回最终得到的字符串。

示例1

输入:s = "abcd", k = 2
输出:"abcd"
解释:没有要删除的内容。

示例2

输入:s = "deeedbbcccbdaa", k = 3
输出:"aa"
解释: 
先删除 "eee""ccc",得到 "ddbbbdaa"
再删除 "bbb",得到 "dddaa"
最后删除 "ddd",得到 "aa"

示例3

输入:s = "pbbcggttciiippooaais", k = 2
输出:"ps"

方式一:使用栈

思路

  • 遍历字符串
  • 移除方式取出栈顶元素
  • 如果栈顶元素为空 或者 栈顶元素不包含ch
  • 将栈顶元素和新字符依次压入栈
  • 否则,判断栈顶元素长度 + 1是否小于k
    • 小于k, 栈顶元素和ch合成新字符,再压入栈

代码

/**
 * @param {string} s
 * @param {number} k
 * @return {string}
 */
const removeDuplicates = function (s, k) {
  const stack = []
  for (const ch of s) {
    // 移除方式取出栈顶元素
    const pre = stack.pop()
    // 栈顶元素为空 或者 栈顶元素不包含ch
    if (!pre || pre.indexOf(ch) === -1) {
      // 将栈顶元素和新字符依次压入栈
      stack.push(pre)
      stack.push(ch)
    } else if (pre.length + 1 < k) {
      // 假设新字符串长度小于k
      // 栈顶元素和ch合成新字符,再压入栈
      stack.push(pre + ch)
    }
  }
  return stack.join('')
}

删除字符串中出现次数 >= 2 次的相邻字符

示例1

输入:"abbbaca"
输出:"ca"
解释:"abbbaca" => "aaca"=>"ca"

思路

  • 出现次数大于等于2的字符需要都移除
  • 遍历放入栈里
  • 取出栈顶的元素,取出当前字符
  • 判断栈顶元素与当前字符是否相等
    • 如果相等,移除栈顶元素,指针往后移动一个位置,再次判断栈顶元素与新位置的字符是否相等,直到不相等为止
    • 如果不等,当前字符压入栈,指针移动一位

代码实现

/**
 * 删除字符串中出现次数 >= 2 次的相邻字符
 * @param {string}s
 */
function removeDuplicate(s) {
  // 记录字符和对应出现的次数
  const stack = []
  let top
  let next
  let p = 0
  while (p < s.length) {
    top = stack[stack.length - 1]
    next = s[p]
    if (next === top) {
      // 出现相邻字符,移除栈顶字符
      stack.pop()
      // 移动指针, 判断下一个元素是否等于栈顶元素,直到不相等为止
      p++
      while (s[p] === top) {
        p++
      }
    } else {
      stack.push(next)
      p++
    }
  }

  return stack.join('')
}