例1: 表达式计算4
题目注意点:
- 出现多余括号时,由于多余括号的可察性(唯一性),我们发现多余括号不可能在中间出现,所以多余括号的位置仅有三种情况(可以叠加):
1.多余括号在左侧出现
2.多余括号在右侧出现
3.多余括号恰好成对出现在最两端 - 能够应对负数情况
- 读入字符串,但是要输出数字
题目思路:
- 通过不断寻找最后一次运算(即运算的最后一步),来递归实现全局运算
- 注意这个最后一次运算肯定不能被括号羁绊,因此在递归开始时,我们要统计括号数量,时刻优化运算式子,来确保运算顺利进行
- 要妥善安排递归中运算符处理顺序
- 可以手写样例测试,增加一A率
ac代码:
#include<bits/stdc++.h>
using namespace std;
string s;
int mypow(int a, int b)
{
int ans =1;
while(b)
{
if(b & 1) ans *= a;
a *= a; b >>= 1;
}
return ans;
}
int change(int l, int r)
{
int x = 0;
for(int i = l; i <= r; i++)
x = x*10 + s[i] - '0';
return x;
}//字符串->整数
int deal(int l, int r)
{
//找最后一次运算
int cnt = 0;//左边还没有消掉的(的个数
int pos1 = -1, pos2 = -1, pos3 =-1;//三类运算
for(int i= l; i<= r; i++)
{
if(s[i] == '(') cnt++;
if(s[i] == ')') cnt--;
if (cnt == 0)
{
if (s[i] == '+' || s[i] == '-') pos1 = i;
if (s[i] == '*' || s[i] == '/') pos2 = i;
if (s[i] == '^' ) pos3 = i;
}
}
//丢掉多余的括号
if (cnt > 0 && s[l] =='(') return deal(l+1, r);
if (cnt < 0 && s[r] ==')') return deal(l, r-1);
//丢掉两端成对的括号
if (s[l] =='(' && s[r] ==')' && pos1+pos2+pos3 == -3)return deal(l+1, r-1);
//分符号左边右边计算
if(pos1 != -1)
if (s[pos1] == '+')return deal(l, pos1-1) + deal(pos1+1, r);
else return deal(l, pos1-1) - deal(pos1+1, r);
if(pos2 != -1)
if (s[pos2] == '*')return deal(l, pos2-1) * deal(pos2+1, r);
else return deal(l, pos2-1) / deal(pos2+1, r);
if(pos3 != -1)
return mypow(deal(l, pos3-1),deal(pos3+1, r));
return change(l, r);
}
int main()
{
cin>>s;
cout << deal(0, s.length()-1) << endl;
return 0;
}
例2:最长合法括号序列
借鉴思路:最长合法括号序列
栈+dp
- f [ i ] f[i] f[i]表示到位置 i i i能够形成的最长合法括号序列的子串的长度
- 如 i i i为正在处理右括号,栈顶为k(k>0),则有状态转移方程: f [ i ] = f [ k − 1 ] + i − k + 1 f[i]=f[k-1]+i-k+1 f[i]=f[k−1]+i−k+1
核心代码:
scanf("%s",c+1); n=strlen(c+1);
for(int i=1;i<=n;i++){
if(c[i]=='(') S.push(i);
else if(!S.empty()){
f[i]=f[S.top()-1]+i-S.top()+1;//转移方程
mx=max(mx,f[i]);
S.pop();
}
}
for(int i=1;i<=n;i++)if(f[i]==mx)ans++;
样例模拟: