题目

image.png

思路

  • 动态规划:
    • 我们用 dp[i] 表示以 i 结尾的最长有效括号;
    • 当 s[i] 为 (,dp[i] 必然等于 0,因为不可能组成有效的括号;那么 s[i] 为 )
      • 当 s[i-1] 为 (,那么 dp[i] = dp[i-2] + 2;
      • 当 s[i-1] 为 ) 并且 s[i-dp[i-1] - 1] 为 (,那么 dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2];
        • dp[i-1]表示以i-1结尾的最长有效括号
        • dp[i-dp[i-1]-2]表示以i-dp[i-1]-2结尾的最长有效括号
      • 比如)()(())为例,设此时i=6
      • dp[i-1]表示i为4、5、的括号长度,此时dp[5]=2
      • dp[i-dp[i-1]-2]=dp[2]表示i为1、2的括号长度 dp[2]=2
      • dp[6] = 2(表示dp[i-1]的括号) + 2(表示新增的两个括号) + 2(表示dp[i-dp[i-1]-2]的括号)
      • 本质就是把两个分割有效的括号连在后计算它的长度
    • image.png
  • 正逆向扫描

    • image.png

      代码

      1. //1.动态规划
      2. public int longestValidParentheses(String s) {
      3. int maxans = 0;
      4. int[] dp = new int[s.length()];
      5. for (int i = 1; i < s.length(); i++) {
      6. if (s.charAt(i) == ')') {
      7. if (s.charAt(i - 1) == '(') {
      8. dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
      9. } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
      10. dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
      11. }
      12. maxans = Math.max(maxans, dp[i]);
      13. }
      14. }
      15. return maxans;
      16. }
      17. //2.栈
      18. public int longestValidParentheses(String s) {
      19. int res = 0;
      20. Stack<Integer> stack = new Stack<>();
      21. stack.push(-1);
      22. for (int i = 0; i < s.length(); i++) {
      23. if (s.charAt(i) == '(') {
      24. stack.push(i);
      25. } else {
      26. stack.pop();
      27. if (stack.isEmpty()) {
      28. stack.push(i);
      29. } else {
      30. res = Math.max(res, i - stack.peek());
      31. }
      32. }
      33. }
      34. return res;
      35. }
      36. //3.正逆向扫描
      37. public int longestValidParentheses(String s) {
      38. int left = 0, right = 0, maxlength = 0;
      39. for (int i = 0; i < s.length(); i++) {
      40. if (s.charAt(i) == '(') {
      41. left++;
      42. } else {
      43. right++;
      44. }
      45. if (left == right) {
      46. maxlength = Math.max(maxlength, 2 * right);
      47. } else if (right > left) {
      48. left = right = 0;
      49. }
      50. }
      51. left = right = 0;
      52. for (int i = s.length() - 1; i >= 0; i--) {
      53. if (s.charAt(i) == '(') {
      54. left++;
      55. } else {
      56. right++;
      57. }
      58. if (left == right) {
      59. maxlength = Math.max(maxlength, 2 * left);
      60. } else if (left > right) {
      61. left = right = 0;
      62. }
      63. }
      64. return maxlength;
      65. }

      最长有效括号