a017. 五則運算

解法一、遞迴

🔹 大式子拆成小式子

依照 優先度由低而高、由後往前 的順序處理
+, -*, /, %(, )

當一個式子沒有任何運算符號 (代表他只剩數字),返回數值
當一個式子運算完成,返回數值

由於括號優先度高 (遞迴中要最後處理)
因此需要一個變數 layer 紀錄當前位置括號的層數
層數 = 0 時,才能處理 +, -, *, /, %

當最左最右都是刮號才去括號

遞迴代碼

(begin1 ~ end1 為前半式子,begin2 ~ end2 為後半式子)

int calculate(int begin, int end){
    // find + -
    return calculate(begin1, end1) [op] calculate(begin2, end2);

    // find * / %
    return calculate(begin1, end1) [op] calculate(begin2, end2);

    // find ( )
    return calculate(begin1, end2);

    // only find number
    return num;
}

12 * 34 * 56 + 78
+ 明顯需要最後處理
於是由後往前找到 +
將問題拆成 [12 * 34 * 56] + [78] 兩個式子遞迴
遞迴會先處理完這兩個式子,再處理加法

以下是完整的步驟 (中括號代表式子的拆法)

  1. + 號:[12 * 34 * 56] + [78]
  2. * 號:[[12 * 34] * 56] + [78]
  3. * 號:[[[12] * [34]] * 56] + [78]
  4. 返回結果:22926

✅ 完整代碼

評分結果(參考) : AC (2ms, 332KB)

#include <bits/stdc++.h>
using namespace std;
#define int long long

string s;

int s2i(int begin_, int end_){
    int num = 0;
    for (int i=begin_; i<end_; i++) {
        num = num*10 + (s[i]-'0');
    }
    return num;
}

int calculate(int begin_, int end_) {

    if (begin_ >= end_) return 0;

    // handle + -
    int layer = 0;
    for(int i=end_-1; i>=begin_; i--) {
        if(s[i] == ')') layer++;
        else if(s[i] == '(') layer--;
        
        else if((s[i] == '+' || s[i] == '-') && layer == 0) {
            if(s[i] == '+') return calculate(begin_, i-1) + calculate(i+2, end_);
            else return calculate(begin_, i-1) - calculate(i+2, end_);
        }
    }

    // handle * / %
    layer = 0;
    for(int i = end_-1; i>=begin_; i--) {
        if(s[i] == ')') layer++;
        else if(s[i] == '(') layer--;
        
        else if(layer == 0) {
            if(s[i] == '*') return calculate(begin_, i-1) * calculate(i+2, end_);
            if(s[i] == '/') return calculate(begin_, i-1) / calculate(i+2, end_);
            if(s[i] == '%') return calculate(begin_, i-1) % calculate(i+2, end_);
        }
    }

    // handle ( )
    if(s[begin_] == '(' && s[end_-1] == ')') {
        return calculate(begin_+2, end_-2);
    }

    return s2i(begin_, end_);
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    while(getline(cin, s)) {
        cout << calculate(0, s.size()) << endl;
    }
}