[路飞]栈的思想&实操上阵-JS

214 阅读4分钟

前言

上篇文章大概介绍了一下栈的定义以及访问形式,这篇就从实操的角度来深入的体验一下栈思想解题的快落。

image.png

前置信息

将Leetcode上面一些比较简洁清晰的栈类型的题梳理了出来,找到了几个典型,下面是题目列表(你需要做的就是,打开leetcode,对照下面的题目列表先审一下题,然后自己思考一小段时间看看能不能解决)。

  1. 20.有效的括号
  2. 682.棒球比赛
  3. 844.比较含退格的字符串
  4. 03.04.化栈为队
  5. 1021.删除最外层的括号

直奔主题

上面的题目大概过一下之后,你的任务就完成了,下面是我这篇文章要做的工作了,来我们先来分析第一题

20.有效的括号

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

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。

思路分析

这期主题是栈,那必须用栈的思路来解决。

创建一个栈,左括号入栈,右括号出栈。最终栈为空,则字符串有效返回true。

如图:

image.png

代码实现


var isValid = function (s) {
    const stack = [];
    for (let i = 0; i < s.length; i++) {
        const len = stack.length;
        switch (s[i]) {
            case "(":
            case "[":
            case "{":
                stack.push(s[i]);
                break;
            case ")":
                if (stack[len - 1] !== "(") return false;
                stack.pop();
                break;
            case "]":
                if (stack[len - 1] !== "[") return false;
                stack.pop();
                break;
            case "}":
                if (stack[len - 1] !== "{") return false;
                stack.pop();
                break;
        }
    }
    return stack.length === 0;
};

682.棒球比赛

给你一个字符串列表,参数规则为,"数字"、“C”、“D”、“+”, “+”表示得分为前两次得分的总和,D表示新回合得分是前一次得分的两倍、C表示前一次得分无效。请你返回记录中得分的总和。

思路分析

遇见数字压栈,遇见符号按照规则出栈,+ 为,栈顶两位数的和再入栈顶,D 为新分数为栈顶数值的两倍,C表示需要删除栈顶元素。

代码实现

var calPoints = function (ops) {
    const stack = [];
    for (let i = 0; i < ops.length; i++) {
        const len = stack.length;
        switch (ops[i]) {
            case "C":
                stack.pop();
                break;
            case "D":
                stack.push(stack[len - 1] * 2);
                break;
            case "+":
                const num = stack[len - 1] + stack[len - 2];
                stack.push(num);
                break;
            default:
                stack.push(Number(ops[i], 10));
                break;
        }
    }
    return stack.reduce((total, next) => {
        return total + next;
    });
};

844. 比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,请你判断二者是否相等。# 代表退格字符。如果相等,返回 true ;否则,返回 false 。

思路分析

创建两个栈,将字符串遍历循环遇见#号删除栈顶元素,遍历完成后对比两个字符串是否相等

代码实现

var backspaceCompare = function (s, t) {
  let stackS = [];
  let stackT = [];

  for (let i = 0; i < s.length; i++) {
    if (s[i] === "#" && stackS.length > 0) {
      stackS.pop();
    }
    if (s[i] !== "#") {
      stackS.push(s[i]);
    }
  }

  for (let i = 0; i < t.length; i++) {
    if (t[i] === "#" && stackT.length > 0) {
      stackT.pop();
    }
    if (t[i] !== "#") {
      stackT.push(t[i]);
    }
  }

  if (stackS.join("") === stackT.join("")) return true;
  return false;
};

03.04.化栈为队

实现一个MyQueue类,该类用两个栈来实现一个队列。

思路分析

栈,先入后出,队列,先进先出。两个栈目的主要是,假设我们有两个栈,A、B,A栈的栈顶元素的依次进入B栈,从而实现A栈取反,最终再将数据从B栈取出,达到队列诉求。

代码实现


var MyQueue = function () {
    this.stackIn = [];
    this.stackOut = [];
};

/**
 * Push element x to the back of queue.
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function (x) {
    this.stackIn.push(x);
};

/**
 * Removes the element from in front of queue and returns that element.
 * @return {number}
 */
MyQueue.prototype.pop = function () {
    this.prepare();
    return this.stackOut.pop();
};

/**
 * Get the front element.
 * @return {number}
 */
MyQueue.prototype.peek = function () {
    this.prepare();
    return this.stackOut[this.stackOut.length - 1];
};

/**
 * Returns whether the queue is empty.
 * @return {boolean}
 */
MyQueue.prototype.empty = function () {
    return !this.stackIn.length && !this.stackOut.length;
};

MyQueue.prototype.prepare = function () {
    if (!this.stackOut.length) {
        while (this.stackIn.length) {
            this.stackOut.push(this.stackIn.pop());
        }
    }
};

1021.删除最外层的括号

将最外层括号删除并返回对应字符

思路分析

这道题最有意思,虽然同样是栈的思维,但是和上面的使用形式不太一样,我们这样来分析,遇见左括号 + 1,遇见右括号 - 1,因此直到数值为0的情况下,我们就获得了当前字符的对应最外层括号,截取字符串并拼接进入对应返回字符。题目解答完毕。

思考:直到数值为0,其实就是当前字符的栈顶元素

因此一定情况下我们也能用数字+-来实现一个栈的思维。

js实现同时也可以复习一下slice的开闭情况,实际测试,左边包含右边不包含。

代码实现

var removeOuterParentheses = function (s) {
    let str = "";
    for (let i = 0, pre = 0, end = 0; i < s.length; i++) {
        if (s[i] === "(") end += 1;
        if (s[i] === ")") end -= 1;
        if (end === 0) {
            str += s.slice(pre + 1, i);
            pre = i + 1;
        }
    }
    return str;
};

总结

以上五道题多管齐下,全部写完一遍后相信你一定能深入理解栈的思维。千里之行始于足下,以后就可以进行更深入的栈类型的知识的学习了哦~

加油思密达~~~~

image.png