20.有效的括号
题目链接:20.有效的括号
文档讲解:代码随想录/有效的括号
视频讲解:视频讲解-有效的括号
状态:已完成(2遍)
解题过程
看到题目的第一想法
这个字符串只包括这六个括号,那结合栈的思维,从左往右遍历,每次有左括号的时候往栈里存一个左括号,遇到右括号的时候把栈pop一个出来看看对不对应。最后全部遍历完了,栈里没剩下的了就没问题。
本来想用charCodeAt来分别,但这三种括号两两之间的asc码差的还不一样,那就直接用字符串本身吧。
手搓一版:
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
const stack = [];
for (let i = 0; i < s.length; i++) {
let kh = s[i];
switch (kh) {
case "{":
stack.push("}");
break;
case "[":
stack.push("]");
break;
case "(":
stack.push(")");
break;
default:
if (s[i]!==stack.pop()) return false;//如果相等不用管,已经pop过了
}
}
return stack.length==0;
};
运行提交都没问题。
看完代码随想录之后的想法
还得是昨天先有了栈思维的基础,看到这题再联想栈的话可以想出解题思路。栈可以很好的在碰到右括号的时候查看离它最近的左括号是什么。
不过文字讲解的代码还是有一版简化版本:
// 简化版本
var isValid = function(s) {
const stack = [],
map = {
"(":")",
"{":"}",
"[":"]"
};
for(const x of s) {
if(x in map) {
stack.push(x);
continue;
};
if(map[stack.pop()] !== x) return false;
}
return !stack.length;
};
总结
看似很复杂的题目,在栈面前确实变得很容易,好东西。
1047.删除字符串中的所有相邻重复项
题目链接:1047.删除字符串中的所有相邻重复项
文档讲解:代码随想录/删除字符串中的所有相邻重复项
视频讲解:视频讲解-删除字符串中的所有相邻重复项
状态:已完成(2遍)
解题过程
看到题目的第一想法
同样还是用栈,拿到一个字母,如果和栈pop出来的字母不一样,那么把pop出来的字母和遍历到的字母一起push进栈;如果遍历到的字母和栈pop出来的字母一样,那不用对栈操作,将遍历的本体删去重复的两个字母。
手搓一版:
/**
* @param {string} s
* @return {string}
*/
var removeDuplicates = function(s) {
const stack = [];
let arrS = s.split('');
let len = s.length;
stack[0] = arrS[0];
for(let i = 1;i<len;){
if(stack.pop()!==arrS[i]){
stack.push(...[arrS[i-1],arrS[i]]);//刚刚pop出去的再加进去
i++;
}else{
arrS.splice(i-1,2);//s中删掉重复的字母
len-=2;
i--;
}
}
return arrS.join('');
};
运行、提交也没问题。
看完代码随想录之后的想法
错付了,说好的栈呢,怎么解法把它当数组看了。这样一整,不用pop出来再push进去,也不用考虑怎么表示栈里最后一个元素是什么了。。。
讲解代码如下:
var removeDuplicates = function(s) {
const result = []
for(const i of s){
if(i === result[result.length-1]){
result.pop()
}else{
result.push(i)
}
}
return result.join('')
};
总结
像这道题和上道题这种消消乐的类型,首先考虑用栈。
二刷的时候直接用了数组的方法哈哈,前端考虑什么堆和栈嘛,数组一步到位。
150.逆波兰表达式求值
题目链接:150.逆波兰表达式求值
文档讲解:代码随想录/逆波兰表达式求值
视频讲解:视频讲解-逆波兰表达式求值
状态:已完成(2遍)
解题过程
看到题目的第一想法
观察了好一阵子题目给出的三个示例,我总结出了,当遍历到是数字的时候,push进栈;当遍历到符号的时候,把栈顶的数字拿出来放到此符号之后再push进去,再将栈顶的三个元素做一下运算,得出来的结果存进栈顶。一直循环往复直到最后。
判断是不是符号和数字我只想到穷举。。待会看看题解怎么说。
手搓一版:
/**
* @param {string[]} tokens
* @return {number}
*/
var evalRPN = function(tokens) {
var isNumber = function(input){
return input !== '+' && input !== '-' && input !== '*' && input !== '/';
};
const stack = [];
for(let i =0;i<tokens.length;i++){
if(!isNumber(tokens[i])){//如果是符号
const x = stack.pop();
stack.push(...[tokens[i],x]);//符号和栈顶的数字交换位置再push进去
let math = eval(stack[stack.length-3]+stack[stack.length-2]+stack[stack.length-1]);//栈顶的三个元素拿出来做运算再存进去
stack.splice(stack.length-3,3,Math.floor(math).toString());
}else{
stack.push(tokens[i]);
}
}
return Number(stack[0]);
};
遇到一个问题,debug之后发现是运算得出 -0.045,floor之后给他变-1了,但题目要变0,改用parseInt试试;提交还只有11/21通过率。debug了一下发现2 - -3这种减负数会出错。受不了了,再写一个函数。
/**
* @param {string[]} tokens
* @return {number}
*/
var evalRPN = function (tokens) {
var isNumber = function (input) {
return input !== '+' && input !== '-' && input !== '*' && input !== '/';
};
var cal = function (num1, operator, num2) {
switch (operator) {
case '+':
return Number(num1) + Number(num2);
case '-':
return Number(num1) - Number(num2);
case '*':
return Number(num1) * Number(num2);
case '/':
return Number(num1) / Number(num2);
}
};
const stack = [];
for (let i = 0; i < tokens.length; i++) {
if (!isNumber(tokens[i])) {//如果是符号
const x = stack.pop();
let math = cal(stack[stack.length - 1],tokens[i],x);//栈顶的两个数字拿出来,中间加入运算符,做运算再存进去
stack.splice(stack.length - 1, 1, parseInt(math).toString());
} else {
stack.push(tokens[i]);
}
}
return Number(stack[0]);
};
终于没问题了!!!!!!!!!
看完代码随想录之后的想法
卧槽,又写啰嗦了。判断是不是数字写复杂了;for循环和做运算也可以写在一起。
文字讲解代码如下:
var evalRPN = function (tokens) {
const stack = [];
for (const token of tokens) {
if (isNaN(Number(token))) { // 非数字
const n2 = stack.pop(); // 出栈两个数字
const n1 = stack.pop();
switch (token) { // 判断运算符类型,算出新数入栈
case "+":
stack.push(n1 + n2);
break;
case "-":
stack.push(n1 - n2);
break;
case "*":
stack.push(n1 * n2);
break;
case "/":
stack.push(n1 / n2 | 0);
break;
}
} else { // 数字
stack.push(Number(token));
}
}
return stack[0]; // 因没有遇到运算符而待在栈中的结果
};
总结
看了示例半天,能悟出来解题思路很满足了,奈何前前后后debug了一个小时,累的ep。判断是不是数字也写复杂了,难顶。
二刷属实没想起来位运算,我用了Math.floor,但是在除以负数的时候会出错,所以要用Math.trunc来代替 | 0 这个位运算 。