NC50999 表达式计算4

题目

题目描述

给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值

数据可能会出现括号情况,还有可能出现多余括号情况

数据保证不会出现 \(\geq 2^{31}\) 的答案

数据可能会出现负数情况

输入描述

仅一行,即为表达式

输出描述

仅一行,既为表达式算出的结果

示例1

输入

(2+2)^(1+1)

输出

16

备注

表达式总长度 \(\leq 30\)

题解

知识点:分治。

按优先级给符号分类,记录每类符号不在括号内的最后一个出现的地方位置,随后找到优先级最低且符号位置存在的位置划分表达式为左右两边,对他们进行相同的操作,然后根据返回表达式值以及对应符号处理得到结果再返回到上一层。

关于匹配括号,引入括号计数器 \(cnt\) 如果为 \(0\) 则说明当前不在任何括号内,只有这时才能够确定符号位置。要注意可能会有多余括号问题,正常情况括号是互相匹配的,而多余的括号会使计数不为 \(0\)

在过程中如果遇到 \(cnt < 0\) ,说明中间有多余右括号,这种括号可以直接删除,不影响后面结果,因此这种情况下也可以确定符号位置,当然为了防止 \()(\) 的反向匹配导致优先级混乱,所以每次确定符号都要把 \(cnt\) 归零。如 $(1+3)) * (3+1) $ 的答案是 \(16\) 不归零就会得到 \(13\)

在遍历完算式后发现没有符号位置,则说明有最外层括号需要清除或者这个是个纯数字,进一步分类如果 \(cnt = 0\) ,再检查外侧是否有括号,决定是纯数字转化或者对称外层括号清除;如果 \(cnt > 0\) ,则有多余外层左括号清除; \(cnt<0\) ,则有多余外层右括号清除。

如存在位置,从低优先级检查位置,进行运算处理。

时间复杂度 平均:\(O(nlogn)\) 最差: \(O(n^2)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

string s;
int StoI(int l, int r) {
    int ans = 0;
    for (int i = l;i <= r;i++) ans = ans * 10 + s[i] - '0';
    return ans;
}

int calc(int l, int r) {
    int cnt = 0;///记录括号数量
    int pos[3] = { -1,-1,-1 };///分别对应+-,*/,^
    for (int i = l;i <= r;i++) {///记录当前子算式不包括在括号内的符号
        //())) + ()
        if (s[i] == '(') cnt++;
        else if (s[i] == ')')cnt--;
        else if (cnt <= 0) {///判断符号是否在括号内,<0异常右端括号失配可以直接忽略(记得清空cnt)
            cnt = 0;///取消右失配括号对后面的影响,原题数据不行
            if (s[i] == '+' || s[i] == '-') pos[0] = i;
            else if (s[i] == '*' || s[i] == '/') pos[1] = i;
            else if (s[i] == '^') pos[2] = i;
        }
    }
    // ((()+())
    // (()+()
    if (!~pos[0] && !~pos[1] && !~pos[2]) {///异常括号或者无符号纯数字导致的无括号外符号的处理
        if (!cnt) {
            if (s[l] == '(') return calc(l + 1, r - 1);///具有对称最外部括号
            else return StoI(l, r);///没有括号的纯数字
        }
        else if (cnt > 0) return calc(l + 1, r);///去掉左括号
        else if (cnt < 0) return calc(l, r - 1);///去掉右括号
    }
    else if (~pos[0]) {
        if (s[pos[0]] == '+') return calc(l, pos[0] - 1) + calc(pos[0] + 1, r);
        else if (s[pos[0]] == '-') return calc(l, pos[0] - 1) - calc(pos[0] + 1, r);
    }
    else if (~pos[1]) {
        if (s[pos[1]] == '*') return calc(l, pos[1] - 1) * calc(pos[1] + 1, r);
        else if (s[pos[1]] == '/') return calc(l, pos[1] - 1) / calc(pos[1] + 1, r);
    }
    else if (~pos[2]) return pow(calc(l, pos[2] - 1), calc(pos[2] + 1, r));
    return 0;///底部返回值,不然过不了编译
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> s;
    cout << calc(0, s.length() - 1) << '\n';
    return 0;
}
posted @ 2022-06-23 18:47  空白菌  阅读(234)  评论(0编辑  收藏  举报