day 11 第五章 栈与队列
今日内容:
● 20. 有效的括号
● 1047. 删除字符串中的所有相邻重复项
● 150. 逆波兰表达式求值
详细布置
20. 有效的括号
【链接】(文章,视频,题目)
讲完了栈实现队列,队列实现栈,接下来就是栈的经典应用了。
大家先自己思考一下 有哪些不匹配的场景,在看视频 我讲的都有哪些场景,落实到代码其实就容易很多了。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html
【第一想法与实现(困难)】直接实现一个栈,发现需要考虑的边界情况较多,代码稍长,不易理解
【看后想法】
-
不匹配的情况有三种:多余左括号,多余右括号,左右数目对但类型不对
-
early return,早返回:字符串长度必须为偶数才可能匹配
-
检测到左括号,但是栈压入右括号,便于出栈的栈顶对比
-
明确栈中存放的内容:等待配对的左括号(但是形式上换成了相应的右括号)
【实现困难】
【自写代码】
class Solution {
public:
bool isValid(string s) {
// 更优雅的栈配对。栈存放的内容是等待配对的左括号(但是形式上换成了相应的右括号)
if (s.size() % 2 != 0) {
return false;
}
std::stack<char> st;
for (char c : s) {
if (c == '(') {
st.push(')');
} else if (c == '[') {
st.push(']');
} else if (c == '{'){
st.push('}');
} else if (st.empty() || st.top() != c) {
// 空栈,缺少左括号;不等说明不配对
return false;
} else { // 相等说明左右匹配,弹出栈顶
st.pop();
}
}
return st.empty(); // 最后栈应该空,非空说明多余左括号
}
};
【收获与时长】35min
【链接】(文章,视频,题目)
1047. 删除字符串中的所有相邻重复项
栈的经典应用。
要知道栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。
题目链接/文章讲解/视频讲解:代码随想录
【第一想法与实现(困难)】
-
暴力,看成类似左右括号配对,配对成功的在栈中删去
-
代码实现的时候自己用了字符串原地修改,由于有额外的使用一个栈,空间复杂度还是O(N)
-
将栈转化回到字符串的时候,下标要特别注意
【看后想法】
-
实现基本一致。使用栈的可以另外定义新的返回字符串,因为已经用了O(N)空间的栈,所以空间利用都差不多
-
还可以用新的字符串自身作为栈
【实现困难】无
【自写代码】
class Solution {
public:
string removeDuplicates(string s) {
// 使用栈
std::stack<char> st;
for (char c : s) {
if (st.empty() || st.top() != c) {
st.push(c);
} else {
st.pop();
}
}
string res = "";
while (!st.empty()) {
res += st.top();
st.pop();
}
std::reverse(res.begin(), res.end());
return res;
}
};
【收获与时长】40min
150. 逆波兰表达式求值
【链接】(文章,视频,题目)
本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题
题目链接/文章讲解/视频讲解:代码随想录
【第一想法与实现(困难)】想不太出来的,直接看题解
【看后想法】
-
用栈存数字,遇到运算符就弹出两个数字
-
注意弹出数字在运算时候的顺序,特别是除法,没有交换律
【实现困难】
【自写代码】
class Solution {
public:
int evalRPN(vector<string>& tokens) {
// 栈存放数字,遇到运算符取两个数字进行计算并压入结果
std::stack<long long> st;
for (const std::string& s : tokens) {
if (s == "+" || s == "-" || s == "*" || s == "/") {
// 注意弹出顺序,特别是num1 / num2
long long num2 = st.top();
st.pop();
long long num1 = st.top();
st.pop();
if (s == "+") {
st.push(num1 + num2);
} else if (s == "-") {
st.push(num1 - num2);
} else if (s == "*") {
st.push(num1 * num2);
} else if (s == "/") {
st.push(num1 / num2);
}
} else {
st.push(std::stoll(s));
}
}
long long res = st.top();
st.pop();
return res;
}
};
【收获与时长】40min
特别注意,力扣题目描述已经说明了,数字本身是最多32位的。此处补充一下,int, long int, long long int的位数区别
一般int = long int,32位,4字节,±2^31 ~= ±2e9
long long int,64位,8字节,±2^63 ~= ±1e19
由于数字本身可能是32位,已经超出了普通int的正负31位,再加上四则运算,所以用long long。