栈经典题目总结(C++实现)
栈是一种后进先出(LIFO)的数据结构,广泛应用于括号匹配、单调栈、字符串解码等问题。本文总结了五道经典的栈问题,帮助你更好地理解和掌握栈的应用。
🟢 1. 有效的括号(Valid Parentheses)
📄 题目描述:
给定一个字符串 s
,包含 '('
、')'
、'{'
、'}'
、'['
和 ']'
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
🧠 解题思路(简洁版)
- 栈 + 哈希表 :
- 使用栈存储最近遇到的左括号。
- 遍历字符串,遇到右括号时检查栈顶是否匹配;若匹配则弹出栈顶,否则返回
false
。 - 最终栈为空则括号有效。
⏱️ 复杂度分析
- 时间复杂度:
O(n)
,其中n
为字符串长度。 - 空间复杂度:
O(n)
,栈空间。
✅ C++ 实现
cpp
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if (n % 2 == 1) {
return false;
}
unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk;
for (char ch : s) {
if (pairs.count(ch)) {
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop();
} else {
stk.push(ch);
}
}
return stk.empty();
}
};
🟢 2. 最小栈(Min Stack)
📄 题目描述:
设计一个支持 push
、pop
、top
和 getMin
操作的栈,所有操作的时间复杂度为 O(1)
。
🧠 解题思路(简洁版)
- 辅助栈 :
- 使用两个栈:
x_stack
存储所有元素,min_stack
存储当前最小值。 - 每次压入元素时,更新
min_stack
的栈顶为当前最小值。 - 弹出元素时,两个栈同步操作。
- 使用两个栈:
⏱️ 复杂度分析
- 时间复杂度:
O(1)
,所有操作均为常数时间。 - 空间复杂度:
O(n)
,辅助栈的空间。
✅ C++ 实现
cpp
class MinStack {
stack<int> x_stack;
stack<int> min_stack;
public:
MinStack() {
min_stack.push(INT_MAX);
}
void push(int val) {
x_stack.push(val);
min_stack.push(min(min_stack.top(), val));
}
void pop() {
x_stack.pop();
min_stack.pop();
}
int top() {
return x_stack.top();
}
int getMin() {
return min_stack.top();
}
};
🟢 3. 字符串解码(Decode String)
📄 题目描述:
给定一个经过编码的字符串,返回其解码后的字符串。编码规则为:k[encoded_string]
,其中 k
是正整数,表示 encoded_string
重复 k
次。
🧠 解题思路(简洁版)
- 栈 + 模拟 :
- 使用栈存储字符串片段。
- 遍历输入字符串,处理数字、字母和括号:
- 数字:提取并压入栈。
- 字母或
[
:直接压入栈。 ]
:弹出栈中的子串并反转,获取重复次数,重复拼接后压入栈。
- 最终将栈中的所有字符串拼接成结果。
⏱️ 复杂度分析
- 时间复杂度:
O(n)
,其中n
为输入字符串长度。 - 空间复杂度:
O(n)
,栈空间。
✅ C++ 实现
cpp
class Solution {
public:
string getDigits(string &s, size_t &ptr) {
string ret = "";
while (isdigit(s[ptr])) {
ret.push_back(s[ptr++]);
}
return ret;
}
string getString(vector<string> &v) {
string ret;
for (const auto &s : v) {
ret += s;
}
return ret;
}
string decodeString(string s) {
vector<string> stk;
size_t ptr = 0;
while (ptr < s.size()) {
char cur = s[ptr];
if (isdigit(cur)) {
string digits = getDigits(s, ptr);
stk.push_back(digits);
} else if (isalpha(cur) || cur == '[') {
stk.push_back(string(1, s[ptr++]));
} else {
ptr++;
vector<string> sub;
while (stk.back() != "[") {
sub.push_back(stk.back());
stk.pop_back();
}
reverse(sub.begin(), sub.end());
stk.pop_back();
int repTime = stoi(stk.back());
stk.pop_back();
string t, o = getString(sub);
while (repTime--) t += o;
stk.push_back(t);
}
}
return getString(stk);
}
};
🟢 4. 每日温度(Daily Temperatures)
📄 题目描述:
给定一个整数数组 temperatures
,表示每天的温度。返回一个数组 answer
,其中 answer[i]
是从第 i
天开始,直到再次出现更高的温度的天数。如果不存在更高的温度,则 answer[i]
为 0。
🧠 解题思路(简洁版)
- 单调栈 :
- 使用栈存储温度数组的索引。
- 遍历温度数组,对于每个温度:
- 若当前温度高于栈顶索引对应的温度,则更新答案并弹出栈顶。
- 将当前索引入栈。
- 最终栈中剩余的索引对应的答案为 0。
⏱️ 复杂度分析
- 时间复杂度:
O(n)
,每个索引最多入栈和出栈一次。 - 空间复杂度:
O(n)
,栈空间。
✅ C++ 实现
cpp
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
vector<int> ans(n);
stack<int> s;
for (int i = 0; i < n; i++) {
while (!s.empty() && temperatures[i] > temperatures[s.top()]) {
int previousIndex = s.top();
ans[previousIndex] = i - previousIndex;
s.pop();
}
s.push(i);
}
return ans;
}
};
🟢 5. 柱状图中最大的矩形(Largest Rectangle in Histogram)
📄 题目描述:
给定一个非负整数数组 heights
,表示柱状图中各个柱子的高度。计算柱状图中最大的矩形面积。
🧠 解题思路(简洁版)
- 单调栈 :
- 使用单调栈分别计算每个柱子的左边界和右边界。
- 左边界:从左到右遍历,栈内存储递增的柱子索引。
- 右边界:从右到左遍历,栈内存储递增的柱子索引。
- 计算每个柱子的最大矩形面积:
(right[i] - left[i] - 1) * heights[i]
。
⏱️ 复杂度分析
- 时间复杂度:
O(n)
,每个柱子最多入栈和出栈一次。 - 空间复杂度:
O(n)
,栈空间。
✅ C++ 实现
cpp
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
vector<int> left(n), right(n);
stack<int> mono_stack;
for (int i = 0; i < n; i++) {
while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
mono_stack.pop();
}
left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
mono_stack.push(i);
}
mono_stack = stack<int>();
for (int i = n - 1; i >= 0; i--) {
while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
mono_stack.pop();
}
right[i] = (mono_stack.empty() ? n : mono_stack.top());
mono_stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; i++) {
ans = max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
};
📌 总结
题目 | 方法 | 时间复杂度 | 空间复杂度 |
---|---|---|---|
有效的括号 | 栈 + 哈希表 | O(n) | O(n) |
最小栈 | 辅助栈 | O(1) | O(n) |
字符串解码 | 栈 + 模拟 | O(n) | O(n) |
每日温度 | 单调栈 | O(n) | O(n) |
柱状图中最大的矩形 | 单调栈 | O(n) | O(n) |
希望本文对你有所帮助!如果你还有其他问题,欢迎继续提问。