Leetcode——栈和队列

Posted 小萝卜鸭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode——栈和队列相关的知识,希望对你有一定的参考价值。

有效的括号

给定一个只包括 ‘(‘‘)‘‘{‘‘}‘‘[‘‘]‘ 的字符串,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。

示例 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 分。
  • ABA + B 分,其中 A 和 B 是平衡括号字符串。
  • (A)2 * A 分,其中 A 是平衡括号字符串。

示例 1:

输入: "()"
输出: 1

示例 2:

输入: "(())"
输出: 2

示例 3:

输入: "()()"
输出: 2

示例 4:

输入: "(()(()))"
输出: 6

提示:

  1. S 是平衡括号字符串,且只含有 ()
  2. 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,其中 AB 都是有效的括号字符串,+ 代表字符串的连接。例如,"""()""(())()""(()(()))" 都是有效的括号字符串。

如果有效字符串 S 非空,且不存在将其拆分为 S = A+B 的方法,我们称其为原语(primitive),其中 AB 都是非空有效括号字符串。

给出一个非空有效字符串 S,考虑将其进行原语化分解,使得:S = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。

S 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S

示例 1:

输入:"(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。

示例 2:

输入:"(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。

示例 3:

输入:"()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""。

提示:

  1. S.length <= 10000
  2. S[i]"("")"
  3. 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,我们需要添加最少的括号( ‘(‘ 或是 ‘)‘,可以在任何位置),以使得到的括号字符串有效。

从形式上讲,只有满足下面几点之一,括号字符串才是有效的:

  • 它是一个空字符串,或者
  • 它可以被写成 ABAB 连接), 其中 AB 都是有效字符串,或者
  • 它可以被写作 (A),其中 A 是有效字符串。

给定一个括号字符串,返回为使结果字符串有效而必须添加的最少括号数。

示例 1:

输入:"())"
输出:1

示例 2:

输入:"((("
输出:3

示例 3:

输入:"()"
输出:0

示例 4:

输入:"()))(("
输出:4

提示:

  1. S.length <= 1000
  2. 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

你需要从字符串中删除最少数目的 ‘(‘ 或者 ‘)‘ (可以删除任意位置的括号),使得剩下的「括号字符串」有效。

请返回任意一个合法字符串。

有效「括号字符串」应当符合以下 任意一条 要求:

  • 空字符串或只包含小写字母的字符串
  • 可以被写作 ABA 连接 B)的字符串,其中 AB 都是有效「括号字符串」
  • 可以被写作 (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——栈和队列的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode通关:栈和队列六连,匹配问题有绝招

LeetCode通关:栈和队列六连,匹配问题有绝招

栈和队列_leetcode341

日常系列LeetCode《10·栈和队列篇》

leetcode刷题记录——栈和队列

LeetCode栈和队列问题