力扣算法题-32.最长有效括号 C语言实现+Java实现

牛客网算法题-括号字符串的最长有效长度
牛客网题目链接

力扣算法题-32.最长有效括号
力扣网题目链接

两道题的意思是一样的,思路是一样的,牛客网的提交需要加上输入。

题目

给定一个括号字符串str,返回最长的能够完全正确匹配括号字符字串的长度。
输入描述:
输出一行字符串,代表str(1<= str length <= 100000)。

输出描述:
输出一个整数,代表括号字符串的最长有效长度。

示例1
输入
(()())
输出
6
示例2
输入
())
输出
2

题目来源:https://www.nowcoder.com/questionTerminal/335acafb6d5141b7873c4b0f24d53c57

最开始见到这个题目的时候,理解错了题目,以至于想的过于简单,()() 这样的情况,返回为2了;
照最后的示例题解来看,这种情况应该最终返回为4。

思路1

若方向条件满足,左括号和右括号数相等的情况下,必定是能够完全匹配的;
方向条件如何满足呢?须满足如下两个条件:
1、从左往右,截至到任意位置,左括号数均大于等于右括号数;
2、从右往左,截至到任意位置,右括号数均大于等于左括号数;
到不满足条件的时候,左右括号数计数归零,从新开始计数。

因此满足以上两个条件情况下,且左右括号数量相等的时候,就是完全匹配的括号字符串
对比取出最长有效长度即可。

程序1

#include <stdio.h>
#include <string.h>

int main(void) {
    /*i 表示循环变量
      ilen 表示字符串长度
      imax 表示最长有效长度中 左括号/右括号的数目
      ileft 表示左括号的计数数目
      iright 表示右括号的计数数目 */
    int i, ilen, imax = 0, ileft = 0, iright = 0;
    char str[100001] = { 0 };
    scanf("%s", str);
    ilen = strlen(str);
    /*从左往右匹配*/
    for (i = 0; i < ilen; i++) {
        if (str[i] == '(') {
            ileft++;
        }
        else if (str[i] == ')') {
            iright++;
            /*左右相等,完全匹配*/
            if (ileft == iright) {
                imax = ileft > imax ? ileft : imax;
            }/*若右括号数大于左括号数,则方向不满足了,归0,计数从新开始*/
            else if (iright > ileft) {
                ileft = 0;
                iright = 0;
            }
        }
    }
    ileft = 0;
    iright = 0;
    /*从右往左匹配*/
    for (i = ilen - 1; i >= 0; i--) {
        if (str[i] == ')') {
            iright++;
        }
        else if (str[i] == '(') {
            ileft++;
            /*左右相等,完全匹配*/
            if (ileft == iright) {
                imax = ileft > imax ? ileft : imax;
            }/*若左括号数大于右括号数,则方向不满足了,归0,计数从新开始*/
            else if (ileft > iright) {
                ileft = 0;
                iright = 0;
            }
        }
    }
    printf("%d\n", 2 * imax);
    return 0;
}

力扣网提交程序

int longestValidParentheses(char * s){
    int ilen, ileft = 0, iright = 0,imax = 0;
    ilen = strlen(s);
    for(int i = 0; i< ilen; i++){
        if(s[i] == '('){
            ileft++;
        }else if(s[i] == ')'){
            iright++;
            if(ileft == iright){
                imax = imax > ileft ? imax : ileft;
            }else if(iright>ileft){
                ileft = 0;
                iright = 0;
            }
        }
    }
    ileft = 0;
    iright = 0;
    for(int i = ilen-1; i >=0; i--){
        if(s[i] == ')'){
            iright++;
        }else if(s[i] == '('){
            ileft++;
            if(ileft == iright){
                imax = imax > ileft ? imax : ileft;
            }else if(ileft>iright){
                ileft = 0;
                iright = 0;
            }
        }
    }
    return 2*imax;
}

思路2

需要考虑的点:
1、如果遇到了左括号,如何找到对应的右括号,遇到对应的右括号,如何找到对应的左括号;
2、如何存储每个完整括号的最长有效长度;
3、什么情况下累计()(((())()()))括号的长度;

声明一个长度和字符串一样长度的数组;用于记录每个括号对应的最长有效长度;
如程序2中做法,找到右括号后,对应左括号的位置分两种情况:
设当前右括号的位置为i,对应左括号的位置为lpos;
1、右括号的左边为左括号,lpos = i - 1;
2、右括号的左边为右括号,lpos = i - 1 - 左边右括号的最长有效长度 num[i-1];

最长长度的计算  (...)((...))
最长长度 = 右括号序列号 - 左括号序列号 + 左括号左边的的右括号的最长有效长度;
               = i - (i - 1 - 左边右括号的最长有效长度num[i-1]) + 1 + num[lpos-1]
               = 2 + num[i-1] + num[lpos - 1]
               
注:先找左括号,再找右括号的做法跟这个类似,思路一样的。

程序2

#include <stdio.h>
#include <string.h>
int main(void) {
	char str[100001] = { 0 };
	scanf("%s", str);
	/*ilen 表示字符串长度
	  i 表示循环变量
	  lpos 表示当前循环中右括号对应的左括号位置
	  imax 表示最长长度 */
	int ilen, i, lpos, imax;
	/*用于记录每个右括号位置上的最长有效长度*/
	int num[100001] = { 0 };
	lpos = 0;
	imax = 0;
	ilen = strlen(str);
	for (i = 1; i < ilen; i++) {
		if (str[i] == ')') {
		    /*基础的情况(),lpos = i-1 
		      若为((...))的情况,需要再减去内层括号的有效长度,即lpos = i-1-num[i-1]*/
			lpos = i - 1 - num[i - 1];
			/*若lpos号大于等于0,且lpos序号为左括号 */
			if (lpos >= 0 && str[lpos] == '(') {
			   /*基础情况() 则num[i]=2;
			     若为((...))的情况,需要加上内层括号的有效长度num[i] = num[i - 1] + 2;
			     若为(...)((...))的情况,需要再加上左边括号的有效长度 num[i] = num[i - 1] + 2 + num[lpos - 1];
			     考虑到 lpos-1 可能为小于0,则最终情况如下 */
				num[i] = num[i - 1] + 2 + (lpos>0 ? num[lpos - 1] : 0);
			}
			/*当前有效长度 num[i] 和imax比较,若大于imax,则赋值给imax */
			imax = imax > num[i] ? imax : num[i];
		}
	}
	printf("%d\n", imax);
	return 0;
}

思路三

动态规划

class Solution {
    public int longestValidParentheses(String s) {
        int maxlen=0;
        int[] cnt = new int[s.length()];
        for(int i=1; i< s.length(); i++){
            if(s.charAt(i) == ')'){
                if(s.charAt(i-1) == '('){
                    cnt[i] = (i>2?cnt[i-2]:0)+2;
                }else if(i-cnt[i-1]-1 >=0 && s.charAt(i-cnt[i-1]-1) == '('){
                    cnt[i] = cnt[i-1]+2+(i-cnt[i-1]>2?cnt[i-cnt[i-1]-2]:0);              
                }
            }
            maxlen = maxlen>cnt[i]?maxlen:cnt[i];
        }
        return maxlen;
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值