遍历&动态规划 添加括号、求括号深度、最长完整括号

95 阅读1分钟

题目

一个完整的括号字符串定义规则如下:

①空字符串是完整的。

②如果s是完整的字符串,那么(s)也是完整的。

③如果s和t是完整的宇符串,将它们连接起来形成的st也是完整的。

例如,"(()())",和"(())()"是完整的括号字符串,"())(","()(",")"是不完整的括号字符串。

牛牛有一个括号字符串s,现在需要在其中任意位置尽量少地添加括号,将其转化为一个完整的括号字符串。请问牛牛至少需要添加多少个括号。

  • 判断是否是完整字符串:通过一个变量count来记录从左往右遇到的"("数量,如果遇到")"则数量减1,如果count<0说明需要添加"(",>0需要添加")",=0时为完整的字符串
  • 如果不是完整字符串:在遍历过程中,如果<0了,则说明要添加1个左括号,此时补齐了成了完整字符串,然后恢复count为0,如果整体遍历结束了count>0了,说明需要添加count数量个右括号,最后答案count+之前过程中补齐的左括号
  • 为什么不能根据遍历完成后count的值来直接添加左括号或右括号,是因为'))((' 最后count为0,但实际上要添加4个括号
function process(str) {
  let count = 0;
  let addLeft = 0;
  for (let i = 0; i < str.length; i++) {
    if (str[i] === "(") {
      count++;
    } else {
      //等价于 count为-1时,添加一个左括号然后将count恢复为0
      if (count === 0) {
        addLeft++;
      } else {
        count--;
      }
    }
  }

  return count + addLeft;
}

题目

在完整字符串的基础上如果给定的字符串都是完整字符串,如果x串深度为x,y串深度为y,则xy串深度为max(x,y),比如:""深度为0,"(())"深度为2,"(())()"深度为max(2,1)为2,计算给定完整字符串的深度

  • 在上一题的基础上,count的最大值就是最大深度,因为每当count为0时,说明一个完整字符串匹配结束

题目

求给字符串中最长完整字符串的长度

  • 首先以"("结尾不可能构成完整字符串所以长度为0,以")"结尾的最长子串等于起-1位置的最长完整子串+2,2为左右边界括号的数量,然后还要加上当前最长子串前面是否还有最长完整子串,不用考虑前面的前面是否还有最长子串,因为是从子问题开始累加,前面的答案已经包含了所有子问题的答案
function process(str) {
  let max = 0;
  const dp = []; // 记录每一个以当前符号结尾的最长完整子串长度

  for (let i = 0; i < str.length; i++) {
    if (str[i] === "(") {
      dp[i] = 0;
    }
  }
  dp[0] = 0;

  for (let i = 1; i < str.length; i++) {
    if (str[i] === ")") {
      const preIndex = i - dp[i - 1] - 1; // 与str[i]配对的'('位置index,中间位置长度为dp[i-1]即")"左边一位的最长完整子串长度
      if (preIndex >= 0 && str[preIndex] === "(") {
        // 当前位置前一位的最长子串+2表示当前位置最长完整子串(x)+ 如果前面还有完整子串(y)
        // 不用担心前面的前面还是完整子串,因为是从子问题开始,每一个最长完整子串的结果都包含了上一次的结果,比如 c 包含了 b, b 包含了 a,d 包含了 c 也就包含了 ba
        dp[i] = dp[i - 1] + 2 + dp[preIndex - 1];
      }
    }
    max = Math.max(max, dp[i]);
  }

  return res;
}