【算法300】:栈02
921. 使括号有效的最少添加
只有满足下面几点之一,括号字符串才是有效的:
它是一个空字符串,或者
它可以被写成 AB (A 与 B 连接), 其中 A 和 B 都是有效字符串,或者
它可以被写作 (A),其中 A 是有效字符串。
给定一个括号字符串 s ,在每一次操作中,你都可以在字符串的任何位置插入一个括号
例如,如果 s = “()))” ,你可以插入一个开始括号为 “(()))” 或结束括号为 “())))” 。
返回 为使结果字符串 s 有效而必须添加的最少括号数。
class Solution {
public:int minAddToMakeValid(string s) {// 当成一个栈的模拟题目来做stack<char> sk;for(auto ch : s){if(ch == '(') sk.push(ch);else {if(sk.size() && sk.top() == '(') sk.pop();else sk.push(ch);}}return sk.size();}
};
946. 验证栈序列
给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:
输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。
class Solution {
public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {// 我们还是直接进行模拟stack<int> sk;int cur = 0;for(auto i : pushed){sk.push(i);while(!sk.empty() && sk.top() == popped[cur]) {sk.pop();++cur;}}return sk.empty();}
};
1190. 反转每对括号间的子串
给出一个字符串 s(仅含有小写英文字母和括号)。
请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。
注意,您的结果中 不应 包含任何括号
class Solution {
public:string reverseParentheses(string s) {string res;stack<string> sk;for(auto ch : s){if(ch == '('){sk.push(res);res = "";}else if(ch == ')'){reverse(res.begin(), res.end());res = sk.top() + res;sk.pop();}else res.push_back(ch);} return res;}
};
1209. 删除字符串中的所有相邻重复项 II
给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。
你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。
在执行完所有删除操作后,返回最终得到的字符串。
本题答案保证唯一。
class Solution {
public:string removeDuplicates(string s, int k) {stack<pair<char,int>> sk;int count = 0;for(auto ch : s){if(!sk.empty() && sk.top().first == ch){count = sk.top().second + 1;sk.push({ch, count});}else {count = 1;sk.push({ch, count});}if(count == k){auto tmp = k;while(tmp--) sk.pop();}}std::string res;while(!sk.empty()){res.push_back(sk.top().first);sk.pop();}reverse(res.begin(), res.end());return res;}
};
84. 柱状图中最大的矩形 (经典的单调栈问题,hard)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
思路:
这道题目的思路可以参考每日温度
这道题目,如果通过暴力的方式,我们将高度作为第一层遍历, 假设height[i]是当前矩形的最低高度,然后我们需要找到左右的最近的< heights[i]的位置, 这个时候我们就可以通过单调栈进行优化,通过两次遍历我们可以找到,每个位置对应的left, right, 为了方便计算,假定-1 和 n位置为负无穷。
class Solution {
public:int largestRectangleArea(vector<int>& heights) {// 通过单调栈的思路来进行解答vector<int> left(heights.size());auto right = left;stack<pair<int,int>> sk;// 填充left arrayfor(int i = 0;i < heights.size();i++){auto value = heights[i];if(sk.size() && value > sk.top().first){left[i] = sk.top().second;sk.push({value, i});}else // size() == 0 || value <= top.first;{while(sk.size() && value <= sk.top().first)sk.pop();left[i] = sk.empty() ? -1 : sk.top().second;sk.push({value, i});}}// 填充right arraysk = stack<pair<int,int>>();for(int i = 0;i < heights.size();i++){auto value = heights[i];while(sk.size() && value < sk.top().first){right[sk.top().second] = i;sk.pop();}sk.push({ value, i });}while(sk.size()){right[sk.top().second] = heights.size();sk.pop();}// 计算最终的结果// // debug// int maxValue = 0;// std::cout << "left array:" << std::endl;// for(auto i : left) std::cout << i << " ";// std::cout << std::endl;// std::cout << "right array: " << std::endl;// for(auto i : right) std::cout << i << " ";// std::cout << std::endl; // //int maxValue = 0;for(int i = 0;i < left.size();i++)maxValue = max(maxValue, heights[i] * (right[i] - left[i] - 1));return maxValue;}
};
316. 去除重复字母
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
class Solution {
public:// 通过hash去重string removeDuplicateLetters(string s) {int Cnt[129] = { 0 };for(auto e : s)Cnt[e]++;bool used[129] = { false };vector<char> res;for(auto e : s){Cnt[e]--;if(used[e]) continue;while(res.size() && res.back() > e && Cnt[res.back()]){used[res.back()] = false;res.pop_back();}res.push_back(e);used[e] = true;}std::string ret;std::copy(res.begin(), res.end(), std::back_inserter(ret));return ret;}
};
85. 最大矩形
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例 1:
输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如上图所示。
示例 2:
输入:matrix = [[“0”]]
输出:0
示例 3:
输入:matrix = [[“1”]]
输出:1
提示:
rows == matrix.length
cols == matrix[0].length
1 <= row, cols <= 200
matrix[i][j] 为 ‘0’ 或 ‘1’
class Solution {
public:// 84题通过单调栈实现的int largestRectangleArea(vector<int>& heights) {// 通过单调栈的思路来进行解答vector<int> left(heights.size());auto right = left;stack<pair<int,int>> sk;// 填充left arrayfor(int i = 0;i < heights.size();i++){auto value = heights[i];if(sk.size() && value > sk.top().first){left[i] = sk.top().second;sk.push({value, i});}else // size() == 0 || value <= top.first;{while(sk.size() && value <= sk.top().first)sk.pop();left[i] = sk.empty() ? -1 : sk.top().second;sk.push({value, i});}}// 填充right arraysk = stack<pair<int,int>>();for(int i = 0;i < heights.size();i++){auto value = heights[i];while(sk.size() && value < sk.top().first){right[sk.top().second] = i;sk.pop();}sk.push({ value, i });}while(sk.size()){right[sk.top().second] = heights.size();sk.pop();}// 计算最终的结果// // debug// int maxValue = 0;// std::cout << "left array:" << std::endl;// for(auto i : left) std::cout << i << " ";// std::cout << std::endl;// std::cout << "right array: " << std::endl;// for(auto i : right) std::cout << i << " ";// std::cout << std::endl; // //int maxValue = 0;for(int i = 0;i < left.size();i++)maxValue = max(maxValue, heights[i] * (right[i] - left[i] - 1));return maxValue;}int maximalRectangle(vector<vector<char>>& matrix) {int m = matrix.size(), n = matrix[0].size();vector<int> heights(n, 0);int maxValue = 0;for(int i = 0;i < m;i++){for(int j = 0;j < n;j++){if(matrix[i][j] == '1')heights[j]++;else heights[j] = 0;}maxValue = std::max(maxValue, largestRectangleArea(heights));}return maxValue;}
};