32、最长有效括号

22 篇文章 0 订阅
20 篇文章 0 订阅

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

输入: "(()"

输出: 2

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

输入: ")()())"

输出: 4

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

方法一: 递归法

思路:使用递归超出内存限制

【1】对于字符串str从左往右数,记录左括号'('和右括号')'的数量。

【2】若出现右括号数>左括号数,则之前记录的都无效,要重新计数。如(())),((​在逗号之前右括号数为3,左括号数位     2,之后的字符串肯定与之前的不匹配,需重新计数。

【3】若出现右括号数等于左括号数,则当前一定有效,比较max与2*左括号数。可能有人举反例"())("​,说左括号数为2,右括号数   为2,但字符串不匹配。但是在数到第2个右括号时,已经出现 右括号数>左括号数,开始重新计数了

【4】若出现左括号数>右括号数,则当前方法不能准确计数。例:((),返回值为0。所以需要从右往左开始计数,条件正确与之前相反。

【5】通过两遍从左往右,从右往左的遍历。我们就能正确的找出最长有效括号数了。

int MAX = 0;
//从左边开始找,当'('数量>')'数量时,不能准确找出有效数量
void l_dpFind(int l_count, int r_count, int index, string s) {
	if (index < s.length()) {
		if (s[index] == '(') {
			++l_count;
		}
		else {
			++r_count;
		}
		if (l_count == r_count) {
			MAX = MAX > 2 * l_count ? MAX : 2 * l_count;

		}
		else if (l_count < r_count) {  //右括号大于左括号,前面的都无效
			l_count = r_count = 0;
		}
		l_dpFind(l_count, r_count, index + 1, s);
	}
}
//从右边开始找
void r_dpFind(int l_count, int r_count, int index, string s) {
	if (index > 0) {
		if (s[index] == ')') {
			++r_count;
		}
		else {
			++l_count;
		}
		if (l_count == r_count) {
			MAX = MAX > 2 * l_count ? MAX : 2 * l_count;
		}
		else if (l_count > r_count) {  //左括号大于右括号,前面的都无效
			l_count = r_count = 0;
		}
		r_dpFind(l_count, r_count, index - 1, s);
	}
}
//将上面两个方法合并之后
void dpFind(int l_count, int r_count, int index, int direction, int end, string s) {
	if (index != end) {
		if (s[index] == ')') {
			++r_count;
		}
		else {
			++l_count;
		}
		if (l_count == r_count) {
			MAX = MAX > 2 * l_count ? MAX : 2 * l_count;
		}
		//从左往右找
		if (direction == 1) {
			if (l_count < r_count) {  //左括号小于右括号,前面的都无效
				l_count = r_count = 0;
			}
		}
		else {
			if (l_count > r_count) {
				l_count = r_count = 0;
			}
		}
		dpFind(l_count, r_count, index + direction, direction, end, s);
	}
}
int longestValidParentheses6(string s) {
	if (s.length() <= 1)
		return 0;
	dpFind(0, 0, 0, 1, s.length(), s);	//从左往右
	dpFind(0, 0, s.length() - 1, -1, -1, s);	//从右往左
	return MAX;
}

方法二:直接遍历

思路:由于方法一使用的递归,系统需要一定的内存空间。在方法一的基础上,我们将递归改成遍历。

int MAX = 0;
//合并之后
void findLongestValid(int l_count, int r_count, int index, int direction, int end, string s) {
	for (;index != end;index += direction) {
		if (s[index] == ')') {
			++r_count;
		}
		else {
			++l_count;
		}
		if (l_count == r_count) {
			MAX = MAX > 2 * l_count ? MAX : 2 * l_count;
		}//从左往右找
		if (direction == 1) {
			if (l_count < r_count) {  //左括号小于右括号,前面的都无效
				l_count = r_count = 0;
			}
		}
		else {
			if (l_count > r_count) {
				l_count = r_count = 0;
			}
		}
	}
}
int longestValidParentheses6(string s) {
	if (s.length() <= 1)
		return 0;
	findLongestValid(0, 0, 0, 1, s.length(), s);	//从左往右
	findLongestValid(0, 0, s.length() - 1, -1, -1, s);	//从右往左
	return MAX;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值