AcWing 150. 括号画家
算法1
栈
括号配对通常用栈,如果发现后括号和栈顶的元素相匹配,那么将其推出。
如果所有元素都是合法(这里的合法是题目定义的),且按顺序入栈(不管是前括号还是后括号都要入栈,只有配对了才弹出),那么最后栈应该是空的;这个问题就是讨论某一括号序列是否合法。
现在给一组括号序列,需要求出最长的合法括号序列的长度。
这里的栈用二元组,第一个元素记录符号,第二记录位置。
如果当中的括号序列时不合法的,也就是乱的,那么后面来的后括号就一定不可能与前面的括号相配对。
那么我们只需要遍历字符串,遇到前括号将其推入栈,配对时弹出栈顶,并记录一次长度(用后括号的位置减去前括号的位置)。
100 pts
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
const int N = 1e5+10;
typedef pair<char, int> PCI;
stack<PCI> s;
bool check(char &a, char &b)
{
if(a == '(' && b == ')') return true;
if(a == '{' && b == '}') return true;
if(a == '[' && b == ']') return true;
return false;
}
int main()
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
char str[N]; cin >> str + 1;
int res = 0;
for(int i = 1; i <= strlen(str + 1); i ++ )
{
if(s.size() && check(s.top().first, str[i]))
{
s.pop();
if(s.size()) res = max(res, i - s.top().second);
else res = max(res, i);
//cout<<i<<" "<<j<<endl;
}
else s.push({str[i], i});
}
cout << res;
return 0;
}
算法2
动态规划
都是\(O(n)\)的时间复杂度,动态规划的代码更简单一些。
我们设\(f_i\)等于以\(i\)结尾的最长合法子串长度。
注意,答案需要取任意\(f_i\)的最大值,而不是\(f_n\)。
分三种情况讨论:
-
如果读入一个前括号,不去动,等到后括号来匹配
-
如果读入后括号,则需要配对。我们假设算法的正确性,那么\(f_{i-1}\)一定表示以前一位结尾的最长合法序列,如下例。很明显\(f_{i-1}\)是中括号当中含两个小括号,那么此时要配对的就是前面的大括号,位置是\(i - f_{i - 1} - 1\),判断这一位置是否匹配再更新。长度加二。
i-1
|
[(){}]{[()()]}
|
i
- 注意,连接两个合法的序列也是合法的操作,那么需要再加上再前一位的f值。
问题迎刃而解。
100 pts
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
char s[N];
int f[N];
int main()
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
cin >> s + 1;
int n = strlen(s + 1);
int res = 0;
for(int i = 2; i <= n; i ++ )
{
if(s[i] == '(' || s[i] == '{' || s[i] == '[') continue;
char c = s[i - f[i - 1] - 1];
if(c =='{' && s[i] == '}' || c =='[' && s[i] == ']' || c =='(' && s[i] == ')') //与之前的括号匹配
f[i] = f[i - 1] + 2, f[i] += f[i - f[i - 1] - 2];
res = max(res, f[i]);
}
cout << res;
return 0;
}
本文来自博客园,作者:{三季野花},转载请注明原文链接:https://www.cnblogs.com/SanGarden/articles/17068748.html