牛客网算法题-括号字符串的最长有效长度
牛客网题目链接
力扣算法题-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;
}
}