单调栈
个人模板
84. 柱状图中最大的矩形 【困难】
【C++】【单调栈】84. 柱状图中最大的矩形 题解:单调栈 | 哨兵技巧(动画来自于编程狂想曲)
注意哨兵技巧,超级好用!
copy()函数是算法标头的库函数,用于复制容器的元素,它将容器的元素从给定范围复制到给定起始位置的另一个容器。
Input:
//declaring & initializing an int array
int arr[] = { 10, 20, 30, 40, 50 };
//vector declaration
vector<int> v1(5);
//copying array elements to the vector
copy(arr, arr + 5, v1.begin());
Output:
//if we print the value
arr: 10 20 30 40 50
v1: 10 20 30 40 50
题解代码:
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int area = 0;
vector<int> newHeights(n+2,0); // 加2个哨兵(小技巧,挺方便的)
copy(heights.begin(), heights.end(), newHeights.begin() + 1);
stack<int> s;
for (int i = 0; i < newHeights.size(); ++i) {
while (!s.empty() && newHeights[s.top()] > newHeights[i]) {
int idx = s.top();
s.pop();
// 栈顶元素pop出后,新栈顶元素就是其左边界!!!!(自己没有考虑这个)
int leftIdx = s.top();
area = max(area, (i - leftIdx - 1) * newHeights[idx]);
}
s.emplace(i);
}
return area;
}
};
经典单调栈的题目。
相关题目:
- 316.去除重复字母(困难)
- 901.股票价格跨度(中等)
- 402.移掉K位数字
- 柱状图中最大的矩形 Hard
剑指 Offer II 039. 直方图最大矩形面积 Hard
类似题:
- 子数组最小乘积的最大值 Medium
- 子数组的最小值之和 Medium
42. 接雨水
class Solution {
public:
int trap(vector<int>& height) {
stack<int> s;
int res = 0;
for (int i = 0; i < height.size(); ++i) {
while (!s.empty() && height[s.top()] < height[i]) {
int curr = s.top();
s.pop();
if (s.empty()) break;
int left = s.top();
int right = i;
int currHight = min(height[left], height[right]) - height[curr];
res += (right - left - 1) * currHight;
}
s.psuh(i);
}
return res;
}
};
739. 每日温度
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> s;
int n = temperatures.size();
vector<int> res(n);
for (int i = 0; i < n; ++i) {
while (!s.empty() && temperatures[s.top()] < temperatures[i]) {
int curr = s.top();
s.pop();
res[curr] = i - curr;
}
s.push(i);
}
return res;
}
};
496. 下一个更大元素 I
class Solution { // 虽然简单但是花了很长时间,┭┮﹏┭┮
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
vector<int> res(m);
unordered_map<int,int> numIdx; // 记录nums2的值和 下一个更大元素II
stack<int> s;
for (int i = 0; i < nums2.size(); ++i) {
numIdx[nums2[i]] = -1; // 设置默认值
while (!s.empty() && s.top() < nums2[i]) {
int curr = s.top();
s.pop();
numIdx[curr] = nums2[i];
}
s.push(nums2[i]);
}
for (int i = 0; i < m; ++i) {
res[i] = numIdx[nums1[i]];
}
return res;
}
};
901. 股票价格跨度
class StockSpanner {
public: // 直接把之前小于的数据删除是我没想到的(可以减少数据量)
stack<pair<int,int>> s;
StockSpanner() {
}
int next(int price) {
pair<int,int> curr(price,1);
while(!s.empty() && s.top().first <= price) {
curr.second += s.top().second;
s.pop();
}
s.push(curr);
return curr.second;
}
};
402. 移掉 K 位数字
// 个人代码,效率贼低
class Solution {
public:
string removeKdigits(string num, int k) {
// 如果后面的数字小于前面的数字则删除前面的数字,使用单调栈
if (k == num.size()) return "0";
stack<int> s;
string res;
for (auto elem : num) {
while (!s.empty() && s.top() > elem && k) {
s.pop();
k--;
}
s.push(elem);
}
// 没有去除任何一个元素
while (k--) s.pop();
// 将s倒出来并反转
while (!s.empty()) {
res += s.top();
s.pop();
}
reverse(res.begin(), res.end());
res.erase(0, res.find_first_not_of("0")); // 去除前置0
return (res == "")?"0":res;
}
};
1081. 不同字符的最小子序列
class Solution {
public:
string smallestSubsequence(string s) {
unordered_map<char,int> numCnt;
int n = s.size();
for (auto elem : s) {
numCnt[elem] += 1;
}
stack<char> stk;
unordered_set<char> exist; //保证该元素是否存在stack中,这个思路很妙(可惜自己没考虑好)
for (auto elem : s) {
if (exist.find(elem) == exist.end()) { // 元素不存在
while (!stk.empty() && stk.top() > elem && numCnt[stk.top()] > 0) {
int curr = stk.top();
exist.erase(curr);
stk.pop();
}
stk.push(elem);
exist.insert(elem);
}
numCnt[elem]--;
}
string res;
while (!stk.empty()) {
res += stk.top();
stk.pop();
}
reverse(res.begin(),res.end());
return res;
}
};
注:316. 去除重复字母与1081题目一致。
402. 移掉 K 位数字
class Solution {
public:
string removeKdigits(string num, int k) {
// 如果后面的数字小于前面的数字则删除前面的数字,使用单调栈
if (k == num.size()) return "0";
stack<int> s;
string res;
for (auto elem : num) {
while (!s.empty() && s.top() > elem && k) {
s.pop();
k--;
}
s.push(elem);
}
// 没有去除任何一个元素
while (k--) s.pop();
// 将s倒出来并反转
while (!s.empty()) {
res += s.top();
s.pop();
}
reverse(res.begin(), res.end());
res.erase(0, res.find_first_not_of("0")); // 去除前置0
return (res == "")?"0":res;
}
};
321. 拼接最大数 (未完成)
1673. 找出最具竞争力的子序列 (未完成)
84. 柱状图中最大的矩形 (未完成)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int area = 0;
vector<int> newHeights(n+2,0); // 加2个哨兵(小技巧,挺方便的)
copy(heights.begin(), heights.end(), newHeights.begin() + 1);
stack<int> s;
for (int i = 0; i < newHeights.size(); ++i) {
while (!s.empty() && newHeights[s.top()] > newHeights[i]) {
int idx = s.top();
s.pop();
// 栈顶元素pop出后,新栈顶元素就是其左边界!!!!(自己没有考虑这个)
int leftIdx = s.top();
area = max(area, (i - leftIdx - 1) * newHeights[idx]);
}
s.emplace(i);
}
return area;
}
};