Leetcode——栈和队列
Posted 小萝卜鸭
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode——栈和队列相关的知识,希望对你有一定的参考价值。
有效的括号
给定一个只包括 ‘(‘
,‘)‘
,‘{‘
,‘}‘
,‘[‘
,‘]‘
的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true
需要用一个栈,开始遍历输入字符串,
如果当前字符为左半边括号时,则将其压入栈中,
如果遇到右半边括号时,若此时栈为空,则直接返回 false,
如不为空,则取出栈顶元素,
若为对应的左半边括号,则继续循环,
反之返回 false
class Solution {
public:
bool isValid(string s) {
stack<char> parentheses;
for (int i = 0; i < s.size(); ++i) {
if (s[i] == ‘(‘ || s[i] == ‘[‘ || s[i] == ‘{‘) parentheses.push(s[i]);
else {
if (parentheses.empty()) return false;
if (s[i] == ‘)‘ && parentheses.top() != ‘(‘) return false;
if (s[i] == ‘]‘ && parentheses.top() != ‘[‘) return false;
if (s[i] == ‘}‘ && parentheses.top() != ‘{‘) return false;
parentheses.pop();
}
}
return parentheses.empty();
}
};
括号的分数
给定一个平衡括号字符串 S
,按下述规则计算该字符串的分数:
()
得 1 分。AB
得A + B
分,其中 A 和 B 是平衡括号字符串。(A)
得2 * A
分,其中 A 是平衡括号字符串。
示例 1:
输入: "()"
输出: 1
示例 2:
输入: "(())"
输出: 2
示例 3:
输入: "()()"
输出: 2
示例 4:
输入: "(()(()))"
输出: 6
提示:
S
是平衡括号字符串,且只含有(
和)
。2 <= S.length <= 50
递归
使用一个计数器,
遇到左括号,计数器自增1,
反之右括号计数器自减1,
那么当计数器为0的时候,就是一个合法的字符串了,
我们对除去最外层的括号的中间内容调用递归,然后把返回值乘以2,
并和1比较,取二者间的较大值加到结果 res 中,
这是因为假如中间是空串,那么返回值是0,乘以2还是0,
但是 "()" 的分值应该是1,所以累加的时候要跟1做比较。
之后记得要更新i都正确的位置
class Solution {
public:
int scoreOfParentheses(string S) {
int res = 0, n = S.size();
for (int i = 0; i < n; ++i) {
if (S[i] == ‘)‘) continue;
int pos = i + 1, cnt = 1;
while (cnt != 0) {
(S[pos++] == ‘(‘) ? ++cnt : --cnt;
}
int cur = scoreOfParentheses(S.substr(i + 1, pos - i - 2));
res += max(2 * cur, 1);
i = pos - 1;
}
return res;
}
};
栈
遍历字符串S,
当遇到左括号时,将当前的分数压入栈中,并把当前得分清0,
若遇到的是右括号,说明此时已经形成了一个完整的合法的括号字符串了,
而且除去外层的括号,内层的得分已经算出来了,就是当前的结果 res,
此时就要乘以2,并且要跟1比较,取二者中的较大值,
然后还要加上栈顶的值,因为栈顶的值是之前合法括号子串的值,跟当前的是并列关系,所以是相加的操作,
最后不要忘了要将栈顶元素移除即可
class Solution {
public:
int scoreOfParentheses(string S) {
int res = 0;
stack<int> st;
for (char c : S) {
if (c == ‘(‘) {
st.push(res);
res = 0;
} else {
res = st.top() + max(res * 2, 1);
st.pop();
}
}
return res;
}
};
删除最外层的括号
有效括号字符串为空 ("")
、"(" + A + ")"
或 A + B
,其中 A
和 B
都是有效的括号字符串,+
代表字符串的连接。例如,""
,"()"
,"(())()"
和 "(()(()))"
都是有效的括号字符串。
如果有效字符串 S
非空,且不存在将其拆分为 S = A+B
的方法,我们称其为原语(primitive),其中 A
和 B
都是非空有效括号字符串。
给出一个非空有效字符串 S
,考虑将其进行原语化分解,使得:S = P_1 + P_2 + ... + P_k
,其中 P_i
是有效括号字符串原语。
对 S
进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S
。
示例 1:
输入:"(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。
示例 2:
输入:"(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。
示例 3:
输入:"()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""。
提示:
S.length <= 10000
S[i]
为"("
或")"
S
是一个有效括号字符串
class Solution {
public:
string removeOuterParentheses(string S) {
int L=1, R=0;
string ans;
for(int i=1; i<S.size(); i++){
if(S[i] == ‘(‘) L++;
else R++;
if(R != L) ans.push_back(S[i]);
else {
i++;
L = 1;
R = 0;
}
}
return ans;
}
};
使括号有效的最少添加
给定一个由 ‘(‘
和 ‘)‘
括号组成的字符串 S
,我们需要添加最少的括号( ‘(‘
或是 ‘)‘
,可以在任何位置),以使得到的括号字符串有效。
从形式上讲,只有满足下面几点之一,括号字符串才是有效的:
- 它是一个空字符串,或者
- 它可以被写成
AB
(A
与B
连接), 其中A
和B
都是有效字符串,或者 - 它可以被写作
(A)
,其中A
是有效字符串。
给定一个括号字符串,返回为使结果字符串有效而必须添加的最少括号数。
示例 1:
输入:"())"
输出:1
示例 2:
输入:"((("
输出:3
示例 3:
输入:"()"
输出:0
示例 4:
输入:"()))(("
输出:4
提示:
S.length <= 1000
S
只包含‘(‘
和‘)‘
字符。
方法一
统计出需要添加的左右括号个数,
这里使用两个变量 left 和 right,分别表示需要的左右括号个数。
遍历字符串S,
若遇到左括号,说明此时需要右括号,则 right 自增1;
若遇到了右括号,
若此时 right 大于0,说明当前的右括号可以用来匹配之前的左括号,不需要另加右括号,所以此时 right 自减1;
而若此时 right 为0,说明当前的右括号前面没有左括号可以跟其匹配,则此时 left 自增1,表示需要额外的左括号。
最后返回 left+right 即为所求
class Solution {
public:
int minAddToMakeValid(string S) {
int left = 0, right = 0;
for (char c : S) {
if (c == ‘(‘) {
++right;
} else if (right > 0) {
--right;
} else {
++left;
}
}
return left + right;
}
};
方法二
只用一个变量 cnt,表示当前左括号的个数。
遍历字符串S,
当遇到左括号,而此时 cnt 为负数时,表示此时右括号是多余左括号的,
而当前遇到的左括号不能匹配之前的右括号,所以将 cnt 的绝对值加到结果 res 中,表示需要这多么的左括号来匹配之前多出的右括号。
然后此时 cnt 自增1,因为当前遇到的是左括号,
若当前遇到右括号,则 cnt 自减1,最终返回 res 加上 cnt 的绝对值即为所求
class Solution {
public:
int minAddToMakeValid(string S) {
int res = 0, cnt = 0;
for (char c : S) {
if (c == ‘(‘) {
if (cnt < 0) {
res += abs(cnt);
cnt = 0;
}
++cnt;
} else {
--cnt;
}
}
return res + abs(cnt);
}
};
反转每对括号间的子串
给出一个字符串 s
(仅含有小写英文字母和括号)。
请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。
注意,您的结果中 不应 包含任何括号。
示例 1:
输入:s = "(abcd)"
输出:"dcba"
示例 2:
输入:s = "(u(love)i)"
输出:"iloveu"
示例 3:
输入:s = "(ed(et(oc))el)"
输出:"leetcode"
示例 4:
输入:s = "a(bcdefghijkl(mno)p)q"
输出:"apmnolkjihgfedcbq"
提示:
0 <= s.length <= 2000
s
中只有小写英文字母和括号- 我们确保所有括号都是成对出现的
class Solution {
public:
string reverseParentheses(string s) {
string res;
stack<string> stk;
for (char &c : s) {
if (c == ‘(‘) {
stk.push(res);
res = "";
} else if (c == ‘)‘) {
reverse(res.begin(), res.end());
res = stk.top() + res;
stk.pop();
} else {
res.push_back(c);
}
}
return res;
}
};
移除无效的括号
给你一个由 ‘(‘
、‘)‘
和小写字母组成的字符串 s
。
你需要从字符串中删除最少数目的 ‘(‘
或者 ‘)‘
(可以删除任意位置的括号),使得剩下的「括号字符串」有效。
请返回任意一个合法字符串。
有效「括号字符串」应当符合以下 任意一条 要求:
- 空字符串或只包含小写字母的字符串
- 可以被写作
AB
(A
连接B
)的字符串,其中A
和B
都是有效「括号字符串」 - 可以被写作
(A)
的字符串,其中A
是一个有效的「括号字符串」
示例 1:
输入:s = "lee(t(c)o)de)"
输出:"lee(t(c)o)de"
解释:"lee(t(co)de)" , "lee(t(c)ode)" 也是一个可行答案。
示例 2:
输入:s = "a)b(c)d"
输出:"ab(c)d"
示例 3:
输入:s = "))(("
输出:""
解释:空字符串也是有效的
示例 4:
输入:s = "(a(b(c)d)"
输出:"a(b(c)d)"
提示:
1 <= s.length <= 10^5
s[i]
可能是‘(‘
、‘)‘
或英文小写字母
遇到字母一律不用考虑,影响结果的只有括号
遍历字符串,遇到字母跳过,遇到‘(’
入栈其对应的索引,遇到‘)’判断栈里面有没有左括号,如果有则弹出栈顶元素,如果没有那么这个‘)’
就必须删除,我们将该位置的‘)’
换为*
。
遍历完之后,如果此时栈非空,那么栈里面的索引对应的‘(’
全要换为 *
。
将s
中的*
全删除即的所需字符串。
class Solution {
public:
string minRemoveToMakeValid(string s) {
stack<int>stk;
int len = s.size();
for(int i = 0;i<len;i++){
if(s[i]==‘(‘)
stk.push(i);
else if(s[i]==‘)‘){
if(!stk.empty())stk.pop();
else s[i]=‘*‘;//标记下待会删掉
}
}
int temp;
while(!stk.empty()){
temp=stk.top();
stk.pop();
s[temp]=‘*‘;
}
s.erase(remove(s.begin(),s.end(),‘*‘),s.end());
return s;
}
};
以上是关于Leetcode——栈和队列的主要内容,如果未能解决你的问题,请参考以下文章