法一:一维dp

  • 子串必须连续
  • 这种涉及子串的,立马要想到

    以 i 结尾

截图_20223301103332.png

  • 以 i 结尾,往左推最多推多长有效?
    • i 位置是 (
    • i 位置是 )
      • 看i - 1 位置的答案, 比如是4, 那么我就看i - 5的字符
        • 如果i - 5位置是 ( , 那么 i 位置的答案至少是6, 然后再看 i - 6结尾的答案能不能跟你续上

image.png

image.png

  • 往前跳着看一遍 (看5位置)就够了,下面说明为什么
    • 截图_20220101110146.png
    • image.png
    • image.png
    • image.png
    • 现在知道为什么 到 i 位置的时候, 只需要往左边看一遍就行了吧, 因为都是累加过来的
      1. public int longestValidParentheses(String s) {
      2. int[] dp = new int[s.length()];
      3. int pre = 0;
      4. int res = 0;
      5. for (int i = 1; i < s.length(); i++) {
      6. if (s.charAt(i) == ')') {
      7. // pre是当前位置的), 应该找哪个位置的左括号
      8. pre = i - dp[i - 1] - 1;
      9. if (pre >= 0 && s.charAt(pre) == '(') {
      10. dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
      11. }
      12. }
      13. res = Math.max(res, dp[i]);
      14. }
      15. return res;
      16. }

      法二:栈

      image.png
      1. public int longestValidParentheses2(String s) {
      2. int max = 0;
      3. //栈里存的是下标
      4. Stack<Integer> stack = new Stack<>();
      5. // 栈底始终要维持一个含义:「最后一个没有被匹配的右括号的下标」
      6. stack.push(-1);
      7. for (int i = 0; i < s.length(); i++) {
      8. if (s.charAt(i) == '(') {
      9. stack.push(i);
      10. } else { // ')'
      11. stack.pop();
      12. if (stack.isEmpty()) {
      13. stack.push(i);
      14. } else {
      15. max = Math.max(max, i - stack.peek());
      16. }
      17. }
      18. }
      19. return max;
      20. }