前言
上篇文章大概介绍了一下栈的定义以及访问形式,这篇就从实操的角度来深入的体验一下栈思想解题的快落。
前置信息
将Leetcode上面一些比较简洁清晰的栈类型的题梳理了出来,找到了几个典型,下面是题目列表(你需要做的就是,打开leetcode,对照下面的题目列表先审一下题,然后自己思考一小段时间看看能不能解决)。
直奔主题
上面的题目大概过一下之后,你的任务就完成了,下面是我这篇文章要做的工作了,来我们先来分析第一题
20.有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
思路分析
这期主题是栈,那必须用栈的思路来解决。
创建一个栈,左括号入栈,右括号出栈。最终栈为空,则字符串有效返回true。
如图:
代码实现
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;
};
总结
以上五道题多管齐下,全部写完一遍后相信你一定能深入理解栈的思维。千里之行始于足下,以后就可以进行更深入的栈类型的知识的学习了哦~
加油思密达~~~~