括号的解析

递归法,假设parse(const string &s, int &idx)函数能解析一层')',内部的递归调用解析掉内层括号

while (idx < N && s[idx] != ')') {
    if (s[idx] == '(') {
        idx++; // (
        auto paren = parse(formula, idx); // 递归解析内层
        idx++; // )
        ...
    } else {
        ...
    }
}

或者用遇'('++、遇')'--的计数来确认合法括号的结束位置(当count==0时)

化学式中各原子数
string countOfAtoms(string formula) {
    int idx = 0;
    auto count = parse(formula, idx);
    ostringstream oss;
    for (auto &e : count) {
        oss << e.first;
        if (e.second > 1) oss << e.second;
    }
    return oss.str();
}

// 解析一层括号
map<string, int> parse(const string &formula, int &idx) {
    const int N = formula.size();
    map<string, int> count;
    while (idx < N && formula[idx] != ')') {
        if (formula[idx] == '(') {
            idx++; // (
            auto paren = parse(formula, idx);
            idx++; // )
            int num = parseNum(formula, idx);
            for (auto &e : paren) { 
                count[e.first] += e.second * num;                    
            }
        } else {
            auto name = parseName(formula, idx);
            int num = parseNum(formula, idx);
            count[name] += num;
        }
    }    
    return count;
}

int parseNum(const string &formula, int &idx) {
    int start = idx;
    while (idx < formula.size() && isdigit(formula[idx])) idx++;
    if (idx == start) return 1;
    return stoi(formula.substr(start, idx - start));
}

string parseName(const string &formula, int &idx) {
    int start = idx;
    idx++; // upper case
    while (idx < formula.size() && islower(formula[idx])) idx++;
    return formula.substr(start, idx - start);
}
解析k[encoded]串
string decodeString(string s) {
    int idx = 0;
    return decodeString(s, idx);
}

// 能decode掉最外一层[xxx]
string decodeString(string &s, int &idx) {
    string ans;
    while (idx < s.size() && s[idx] != ']') {
        if (isalpha(s[idx])) {
            ans += s[idx];
            idx++;
        } else { // 数字开头
            int num = 0;
            while (idx < s.size() && isdigit(s[idx])) {
                num = num * 10 + s[idx] - '0';
                idx++;
            }
            idx++; // [
            string sub = decodeString(s, idx);
            idx++; // ]
            while (num--) ans += sub;
        }
    }
    return ans;
}

加减乘除计算

i和ii是iii的特例,iii的栈解法如下

int calculate(string &s) {
    // 中缀转后缀,用nums栈和ops栈
    // 遇到下一个优先级<=栈顶的op时、先弹出计算再把op入栈。
    // 左括号'('先入栈,等遇到右括号')'时不断弹出计算直到'(';
    // 左括号只能遇右括号时弹出,将'('的优先级设为最小,以防止被其他op计算误弹出。
    unordered_map<char, int> priority = {
        {'*', 2}, {'/', 2},
        {'+', 1}, {'-', 1},
        {'(', 0},
    };

    stack<int> nums;
    stack<char> ops;
    for (int i = 0; i < s.size(); i++) {
        char c = s[i];
        if (c == ' ') continue;
        if (isdigit(c)) {
            // 因为最后会i++,这里解析完num后i指针必须停在最后一位数字上
            int num = c - '0';
            while (i + 1 < s.size() && isdigit(s[i+1]))
                num = num * 10 + s[++i] - '0';
            nums.push(num);
        } else if (c == '(') {
            ops.push(c);
        } else if (c == ')') {
            while (ops.top() != '(') 
                calc(nums, ops);
            ops.pop(); // 弹出'('
        } else { // +-*/
            while (!ops.empty() && priority[c] <= priority[ops.top()])
                calc(nums, ops);
            ops.push(c);
        }
    }
    while (!ops.empty())
        calc(nums, ops);

    return nums.top();
}

void calc(stack<int> &nums, stack<char> &ops) {
    if (ops.empty() || nums.size() < 2) return;
    char op = ops.top(); ops.pop();
    int val2 = nums.top(); nums.pop();
    int val1 = nums.top(); nums.pop();

    if (op == '*') {
        nums.push(val1 * val2);
    } else if (op == '/') {
        nums.push(val1 / val2);
    } else if (op == '+') {
        nums.push(val1 + val2);
    } else if (op == '-') {
        nums.push(val1 - val2);
    }
}