leetcode32-最长括号匹配-栈实现

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

 

示例 1:

 

输入: "(()"

输出: 2

解释: 最长有效括号子串为 "()"

示例 2:

 

输入: ")()())"

输出: 4

解释: 最长有效括号子串为 "()()"

 

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/longest-valid-parentheses

 

解决方案1,通过栈来解决

常用的括号匹配都是使用栈来解决,通过栈可以很容易的找到栈的匹配。

这个问题,可以分解:

  1. 连续的括号的求解。
  2. 分段的括号数求解问题
  3. 求最大的连接括号数。

 

 

连续括号求解 

连接括号的求解问题,这个比较容易,可以直接使用栈来实现

/**
 *
连续括号的求解问题
 
*
 * @param
s
 
* @return
 
*/

public int parenthess(String s) {
 
if (null == s || s.length() < 1) {
   
return 0;
 
}

 
char[] data = s.toCharArray();
  int
length = 0;

 
Stack<Character> stack = new Stack<>();

  for
(int i = 0; i < data.length; i++) {
   
// 左括号进行压栈操作
   
if (data[i] == LEFT_PARENTHESS) {
      stack.push(data[i])
;
   
} else {
     
// 在匹配上右括号时,弹出一个左括号,长度++
      //
只需要统计左括号,即可*2就可得到总匹配括号数
     
if (!stack.isEmpty()) {
        stack.pop()
;
       
length++;
     
}
    }
  }

 
return length * 2;
}

 

这个代码比较简单,通过统计左括号的数量*2,即可得到总的匹配括号数。

 

分段的括号数求解问题

刚刚的代码只能统计连接的括号,如果出现不连接的就会出现问题。

怎么解决这个问题呢?我的思路这样子的

只需要加入一个变量来记录下不匹配的位置即可,

那不连续的位置在哪里?

我觉得满足这两个条件:

  1. 栈为空
  2. 当前为右括号。

满足这两个条件,将位置记录下来。

 

/**

 * 分段连续括号的求解问题

 *

 * @param s

 * @return

 */

  public int parenthessSegment(String s) {

  if (null == s || s.length() < 1) {

    return 0;

  }

  

  char[] data = s.toCharArray();

  int length = 0;

  int badIndex = -1;

  

  Stack<Character> stack = new Stack<>();

  

  for (int i = 0; i < data.length; i++) {

    // 左括号进行压栈操作

    if (data[i] == LEFT_PARENTHESS) {

      stack.push(data[i]);

    } else {

      // 在匹配上右括号时,弹出一个左括号,长度++

      // 只需要统计左括号,即可*2就可得到总匹配括号数

      if (!stack.isEmpty()) {

        stack.pop();

        length++;

      } else {

        badIndex = i;

      }

    }

  }

  

  return length * 2 - badIndex;

  }

 

当不连接括号出现为右括号时,可以进行正确的验证。

例如:“())(((()))”

 

但是,如果出现不连续的括号为左括号呢?那是否还能正确匹配呢?

例如: “()((((()))”

答案是不能的,我们的匹配规则是按照左括号压栈操作,右括号进行配对操作。但现在不匹对的是左括号,全部压入了栈。而判断条件是栈为空,并且当前为右括号,条件不满足。需要对此问题进行修正。

 

我们对栈中的存储进行下修改,之前是存储括号,现在改为存储左括号的索引下标

通过不匹配的位置badindex=-1开始

当栈遍历到索引下标为1时,括号发生配对,索引为0的左括号被弹出栈

现在计算括号数,有此规则当前索引号减去不匹配的位置=括号数

即1-(-1)=2

当遍历到索引为7时,栈中的元素,发生匹配,索引6被弹出,计算7的连接括号数,

有此规则,当前索引号减去栈顶的索引号=连接括号数。

索引7的连接括号数: = 7- 5 = 2

是否后续也有如此规则,再看下索引8

索引8的连接括号数:8-4=4

 

那用代码实现出来,就是这样子:

 

/**

 * 分段连续括号的求解问题

 *

 * @param s

 * @return

 */

  public int parenthessSegment(String s) {

  if (null == s || s.length() < 1) {

    return 0;

  }

  

  char[] data = s.toCharArray();

  int length = 0;

  int badIndex = -1;

  

  Stack<Integer> stack = new Stack<>();

  

  for (int i = 0; i < data.length; i++) {

    // 左括号进行压栈操作

    if (data[i] == LEFT_PARENTHESS) {

      stack.push(i);

    } else {

      // 在匹配上右括号时

      if (!stack.isEmpty()) {

        stack.pop();

        // 如果还存在元素,则使用当前索引减栈顶索引

        if (!stack.isEmpty()) {

          length = i - stack.peek();

        }

        // 当前已经为空了,说明需要命名用上次出现不匹配的位置.

        else {

          length = i - badIndex;

        }

      } else {

        badIndex = i;

      }

    }

  }

  

  return length;

  }

 

到现在为止,已经能求解连接的括号数了。

 

求最大的连接括号数

这个题目的要求是求解最长的匹配括号数。

这个就比较容易了,只需要判断下,留下最大的括号数即可

/**

 * 分段连续括号的求解问题,最终解决

 *

 * @param s

 * @return

 */

  public int parenthessLast(String s) {

  if (null == s || s.length() < 1) {

    return 0;

  }

  

  char[] data = s.toCharArray();

  int length = 0;

  int badIndex = -1;

  int maxLengthParenthess = 0;

  

  Stack<Integer> stack = new Stack<>();

  

  for (int i = 0; i < data.length; i++) {

    // 左括号进行压栈操作

    if (data[i] == LEFT_PARENTHESS) {

      stack.push(i);

    } else {

      // 在匹配上右括号时

      if (!stack.isEmpty()) {

        stack.pop();

        // 如果还存在元素,则使用当前索引减栈顶索引

        if (!stack.isEmpty()) {

          length = i - stack.peek();

        }

        // 当前已经为空了,说明需要命名用上次出现不匹配的位置.

        else {

          length = i - badIndex;

        }

        if (length > maxLengthParenthess) {

          maxLengthParenthess = length;

        }

      } else {

        badIndex = i;

      }

    }

  }

  

  return maxLengthParenthess;

  }

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值