leetcode32.最长有效括号(困难)

在这里插入图片描述
在这里插入图片描述
自己一开始不会做。。。
1:看到最长子串,首先想到的是DP?但是转移方程怎么列?没头绪啊(见方法一)
2:看到是括号匹配,想到用栈,但是暴力出每个子串,然后用栈来判断,O(n^3)的复杂度,很明显会超时,怎么做?(见方法二)
3:想到’(‘加一,’)‘减一,判断是否等于0来判断是否匹配,然而出现’)('怎么处理?(见方法三)

方法一:DP,时间空间都是O(n)
dp[i]表示以s[i]结尾的最长子串。
case1:当前字符是’(‘,必然不匹配。
case2:当前字符s[i]是’)’
---------------若前一个字符s[i-1]是’(‘,则,dp[i]=dp[i - 2] + 2;
---------------若s[i-1]是’)‘,若s[i-1]前面不匹配的第一个字符:s[i-1-dp[i-1]]是’(',dp[i]=dp[i-1]+2+dp[i-1-dp[i-1] - 1]。注意要加dp[i-1-dp[i-1] - 1]!!!
易错点:注意下标不能越界!!!

class Solution {
public:
    int longestValidParentheses(string s) {
        //DP
        int n = s.size();
        vector<int> dp(n);
        int ans = 0;
        for (int i = 0;i < n; ++i) {
            if (s[i] == ')') {
                if (i - 1 >= 0 && s[i - 1] == '(') {
                    dp[i] = i - 2 >= 0 ? dp[i - 2] + 2 : 2;
                }
                if (i - 1 >= 0 && s[i - 1] == ')') {
                    int index = i - 1 - dp[i - 1]; //s[i-1]左边第一个不匹配的位置
                    if (index >= 0 && s[index] == '(') {
                        dp[i] = index - 1 >= 0 ? dp[i - 1] + dp[index - 1] + 2 : dp[i - 1] + 2;
                    }
                }
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

方法二:栈,时间空间都是O(n)
难点: 栈顶放左边第一个不匹配的字符的下标
具体为:
如果当前字符为’(‘,直接把下标入栈
如果当前字符为’)‘:如果栈顶是’(‘,出栈,并计算出匹配的长度更新ans;否则把下标入栈。
易错点:
1:更新的时候:当前下标减去栈顶不匹配的下标,而不是减去栈顶’('的下标!!!
2:为了方便边界判断,栈底先放一个-1

class Solution {
public:
    int longestValidParentheses(string s) {

        stack<int> st;
        st.push(-1);
        int n = s.size(), ans = 0;
        for (int i = 0; i < n; ++i) {
            if (s[i] == '(') st.push(i);
            else {
                int index = st.top();
                if (index != -1 && s[index] == '(') {
                    st.pop();
                    int tmp = i - st.top();
                    ans = max(tmp, ans);
                }else {
                    st.push(i); 
                }
            }
        }
        return ans;
    }
};

方法三:双指针,时间O(n),空间O(1)
难点:
从左往右扫描,如果’)‘大于’(‘的数量,nums1 nums2都置为0!!!
具体为:
num1记录‘(’的个数,nums2记录‘ )‘的个数。
从左往右扫描,如果’)‘大于’(‘的数量,nums1 nums2都置为0,如果num1== nums2则匹配,更新ans
易错点:
上面这样会忽略’’(()"的情况,解决方案是,从右向左也扫描一遍,如果’(‘大于’)'的数量,nums1 nums2都置为0,如果num1==nums2则匹配,更新ans。

class Solution {
public:
    int longestValidParentheses(string s) {
        
        int nums1 = 0, nums2 = 0, n = s.size(), ans = 0; //分别记录左括号和右括号的数量
        for (int i = 0; i < n; ++i) {
            if (s[i] == '(') nums1++;
            else nums2++;
            if (nums1 == nums2) {
                ans = max(ans, 2 * nums1);
            }else if (nums2 > nums1) {
                nums1 = nums2 = 0;
            }
        }
        nums1 = nums2 = 0;
        for (int i = n - 1; i >= 0; --i) {
            if (s[i] == '(') nums1++;
            else nums2++;
            if (nums1 == nums2) {
                ans = max(ans, 2 * nums1);
            }else if (nums2 < nums1) {
                nums1 = nums2 = 0;
            }
        }
        return ans;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值