目录
1. 有效的括号
https://leetcode-cn.com/problems/valid-parentheses/
思路:栈, 左括号进,右括号出
class Solution {
public:
bool isValid(string s) {
// 1.初始化准备
stack<char> stk;
unordered_map<char, char> mp = {
{'(', ')'},
{'[', ']'},
{'{', '}'}
};
// 2.正式遍历
for (const auto &c : s) {
if (mp.count(c) != 0) {
stk.push(c);
}
else if (stk.empty() || mp[stk.top()] != c) {
return false;
}
else {
stk.pop();
}
}
// 3.后处理
return stk.empty();
}
};
时间复杂度O(n), 空间复杂度O(n)
2. 最小栈
https://leetcode-cn.com/problems/min-stack/
思路:使用辅助栈
class MinStack {
private:
vector<int> stk;
vector<int> vmin;
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int val) {
stk.push_back(val);
if (vmin.empty() || vmin.back() > val) {
vmin.push_back(val);
}
else {
vmin.push_back(vmin.back());
}
}
void pop() {
stk.pop_back();
vmin.pop_back();
}
int top() {
return stk.back();
}
int getMin() {
return vmin.back();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
时间复杂度O(1), 空间复杂度O(n)
3. 回文链表
https://leetcode-cn.com/problems/palindrome-linked-list/
思路: 可以使用栈, 两次遍历
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
// 1.初始化准备
stack<int> stk;
// 2.第一次遍历,压栈
ListNode* curr = head;
while (curr) {
stk.push(curr->val);
curr = curr->next;
}
// 3.第二次遍历,出栈并检查
curr = head;
while (curr) {
if (curr->val != stk.top()) {
return false;
}
else {
stk.pop();
}
curr = curr->next;
}
return true;
}
};
时间复杂度O(n), 空间复杂度O(n)
4. 单调栈
解法一:暴力解法
class Solution {
public:
// 暴力解法:遍历每一个柱子,向两边找小于该柱子高度的柱子,最终可以确定矩形宽度
// 然后求出最大值, 会超时
int largestRectangleArea(vector<int>& heights) {
int ans = 0;
for (int i=0; i<heights.size(); ++i) {
int left = i;
int right = i;
while (left >= 0 && heights[left] >= heights[i]) {
--left;
}
left = left == -1 ? 0 : (left+1);
while (right < heights.size() && heights[right] >= heights[i]) {
++right;
}
right = right == heights.size() ? (heights.size() - 1) : (right - 1);
int width = right - left + 1;
int area = heights[i] * width;
if (area > ans) {
ans = area;
}
}
return ans;
}
};
时间复杂度O(n^2),空间复杂O(1)
解法二:单调栈
关键点:
- 利用辅助前后哨兵就不用处理空栈的特殊情况,以及不用对最后的栈做特殊处理
- 最核心的是矩形宽的计算,等于当前索引检索减少该栈中去前一个的元素,再减去1
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
// 1.为了简化栈处理,设置前后哨兵,
// 这样不会有空栈,而且最后也不用对剩余栈进行特殊处理
vector<int> new_heights;
new_heights.push_back(-1);
for (auto &m : heights) {
new_heights.push_back(m);
}
new_heights.push_back(-1);
// 2.正式遍历处理
stack<int> stk; //单调不减栈,存放的是索引,因为索引需要用到,同时高度可以通过数组索引得到
int ans = 0; //存放结果
stk.push(0); //栈首个元素为索引0
for (int i=1; i<new_heights.size(); ++i) {
// 2.1 当前高度大于等于栈顶高度
if (new_heights[i] >= new_heights[stk.top()]) {
stk.push(i);
}
// 2.2 当前高度小于栈顶高度
else {
while (new_heights[i] < new_heights[stk.top()]) {
// 关键的是宽的计算:等于当前索引检索减少该栈中去前一个的索引,再减去1
int top = stk.top();
stk.pop();
int area = new_heights[top] * (i - stk.top() - 1);
ans = area > ans ? area : ans;
}
stk.push(i);
}
}
return ans;
}
};
时间复杂度O(n)(每个元素进出栈一次),空间复杂度O(n)