LeetCode HOT100 - 最长有效括号

首先同样考虑之前提过的有效括号的形式

也就是 左括号的数量等于右括号,且中间过程中右括号不能大于左括号

如果不考虑后者的限制的话其实思路挺简单的,就是维护前缀和数组,维护每个前缀和第一次出现的位置

但是这样我们没法顾及到那个限制,因为我们仅考虑前缀和的话,相当于只保证了内部的个数是相同的,但是顺序是不一定的

可这个形式感觉是可以继续考虑的

因为要求是连续的

所以如果右括号大于左括号了,那么前后一定是割裂了,也就是中间这一段肯定是没法用了,类似于最大连续子段和的思路,一定用不上了,那么直接清空,重新开始计数

但即使这样我们还是没法使用 map ,理由和上面是相同的,比如 "()(()" , )(() 统计值也是 0,而且遍历的过程中 )< ( 的情况也没有出现,但是选择子序列可能会出现这样的情况

合理的方式是使用 l, r 计数,而且我们只在 l == r 时更新答案

因为我们相当于只看那个上一个 l = r = 0 为起点的情况,因为这样的计数我们只能保证这个起点的连续段是前缀不会出现问题的

所以相当于只有前缀和为 0 才更新答案

而 l > r 时表示当前候选段虽然“没有坏前缀”,但是它还没闭合

那么关于 ((),正向显然是找不到的,这时候我们就逆序找一遍

因为正向反向总有一个是能看到的

重点就是这个合法判断,大区间满足合法不代表小区间合法

class Solution {
public:
    int longestValidParentheses(string s) {
        int l = 0, r = 0;
        int n = s.size();
        int ans1 = 0;
        int ans2 = 0;
        {
            for (int i = 0; i < n; i++) {
                if (s[i] == '(') {
                    l++;
                } else {
                    r++;
                }
                cout << i << ' ' << l << ' ' << r << '\n';
                if (r > l) {
                    l = 0, r = 0;
                    continue;
                } else if (r == l) {
                    ans1 = max(ans1, min(r, l));
                }
            }
        }
        reverse(s.begin(), s.end());
        l = 0, r = 0;
        {
            for (int i = 0; i < n; i++) {
                if (s[i] == ')') {
                    l++;
                } else {
                    r++;
                }
                cout << i << ' ' << l << ' ' << r << '\n';
                if (r > l) {
                    l = 0, r = 0;
                    continue;
                } else if (r == l) {
                    ans2 = max(ans2, min(r, l));
                }
            }
        }
        return max(ans1, ans2) * 2;
    }
};
posted @ 2026-04-14 22:44  rdcamelot  阅读(21)  评论(0)    收藏  举报