数据结构--括号问题汇总

1.有效的括号
leetcode 20
考虑到有效匹配的问题,可以采用栈的方法,每次匹配上一个栈顶的字符,不符合就返回,将左括号放入栈中,用右括号去匹配,思路如下:

class Solution {
public:
    char returnWord(char c){
        char res = '0';
        switch(c){
            case ')':
                res = '('; 
                break;
            case '}':
                res = '{';
                break;
            case ']':
                res = '[';
                break;
            default:
                break;
        }
        return res;
    }
    bool isValid(string s) {
        stack<char> st; //建立一个栈
        if(s.size()==0)
            return true;
        if(s.size()&1)    //考虑不符合的输入情况
            return false;
        int n = s.size();
        for(int i=0; i<n; i++){
            if(s[i]=='(' || s[i]=='[' || s[i]=='{')
                st.push(s[i]);
            else{
                if(st.empty() || returnWord(s[i])!=st.top()) // 调用函数去匹配,也可以采用哈希表去匹配,没有匹配成功或者没有带匹配的元素,即返回失败
                    return false;
                else
                    st.pop();
            }
        }
        return st.empty();
    }
};

2.括号生成
leetcode 22
需要返回所有满足的有效括号集合,可以采用深度优先遍历的解法,不符合的结果进行剪枝,解法如下:

class Solution {
public:
    vector<string> res;  //全局变量用于返回
    vector<string> generateParenthesis(int n) {
        string tmp;
        dfs(tmp, n, 0, 0);
        return res;
    }
    void dfs(string tmp, int n, int left, int right){ //深度优先遍历
        if(left>n || right>left)  //左括号超过目标数量,右括号比左括号多
            return;
        if(tmp.size()==2*n){      //经过筛选后所得即为结果
            res.push_back(tmp);
            return;
        }
        dfs(tmp+"(", n, left+1, right);
        dfs(tmp+")", n, left, right+1);
    }   
};

3.最长有效括号
leetcode 32
解法一:用栈解决,利用指针移动,选取匹配元素开始的位置,每次将左括号的位置入栈,然后匹配到右括号时,计算此时的最大长度,如果此时栈里面没有元素时,直接计算当前长度,栈里面还有元素时需要,考虑可能是中间多个元素匹配后得长度,需要计算此时位置与栈顶元素的长度差,如果来了一个右括号但没有匹配成功就要更新开始元素位置,代码如下:

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        int ans = 0;
        int start = 0;
        for (int i = 0; i < s.size(); i++) 
        {
            if (s[i] == '(') 
                st.push(i);              
            else 
            {
                if (!st.empty()) 
                {
                    st.pop();	
                    if (st.empty()) 
                        ans = max(ans, i - start + 1);
                    else  
                        ans = max(ans, i - st.top());
                }
                else  
                    start = i + 1;                      
            }
        }
        return ans;
    }
};

解法二:动态规划
定义一个数组DP[i],状态i为以i结尾的元素的最长有效括号数;
第一种情况:
当第i个元素为左括号时,以它结尾的有效括号长度为0,
第二种情况:
当第i个元素为右括号时,开始与前面元素匹配最长有效括号
(1)如果前一个元素为左括号,直接匹配成功,且最长有效括号长度要加上i-2元素位置的有效括号长度
(2)如果前一个元素为右括号,则判断i-1位置元素是否是有效的,如果有效则判断i-dp[i-1]-1位置的元素是否是左括号,是的话则匹配成功,且需进一步判断是否因为此次匹配成功,前面i-dp[i-1]-2位置的有效括号是否能加入此次匹配的最长长度中
注意:每次索引数组下标需要判断下是否有效
代码如下:

class Solution {
public:
    int longestValidParentheses(string s) {
    int n = s.size();
    vector<int> dp(n);
    int res = 0;
    for(int i=1; i<n; i++){
        if(s[i]==')'){
            if(s[i-1]=='('){
                dp[i] = i>=2 ? (dp[i-2]+2) : 2;
            }
            else if(dp[i-1]>0){
                //dp[i] = dp[i-1];
                if(i-dp[i-1]-1>=0 && s[i-dp[i-1]-1]=='('){
                    dp[i] = 2 + dp[i-1];
                
                    if(i-dp[i-1]-2>=0){
                        dp[i] = 2 + dp[i-1] + dp[i-dp[i-1]-2];
                    }
                }
            }
        }
        res = max(res, dp[i]);
    }
    return res;
    }
};

4.有效的括号字符串
leetcode678
栈解决:
定义两个栈,一个用于存储左括号,一个用于存储星号,第一遍遍历,用两个栈来比较看是否能够存在匹配的有效字符串,并将下标元素其存入栈中
第二遍查看星号的下标是否位于左括号的右侧,符合一对则pop出来,最后如果左括号栈还有没有匹配的元素则返回false
代码如下:

class Solution {
public:
    bool checkValidString(string s) {
        stack<int> left;  //存储左括号
        stack<int> middle; //存储星号
        int n = s.size();
        for(int i=0; i<n; i++){
            if(s[i]=='(')
                left.push(i);
            else if(s[i]==')'){
                if(!left.empty()){
                    left.pop();
                }
                else if(!middle.empty()){
                    middle.pop();
                }
                else{
                    return false;
                }
            }
            else{
                middle.push(i);
            }
        }
        while(!middle.empty()){
            if(!left.empty()){
                if(left.top()>middle.top()){
                    return false;
                }
                left.pop();
                
            }
            middle.pop();
        }
        return left.empty();
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值