Expression All

// 第三轮 coding 公式计算
// 第一小问 input : ["T2", ["T1 = 1", "T2 = T3", "T3 = T1"]] output : T2值   公式都是左边一个变量, 右边是变量或者数值
// 第二小问 input : ["T2", ["T1 = 1", "T2 = 2 + T4", "T3 = T1 - 4", "T4 = T1 + T3]]  output:T2值
// 公式左边为变量,右边为一个或多个变量 / 数值,包括加减操作
// 第三小问: 在第二小问基础上可能存在解不出的情况
// 这道题我是用topological sort的方法,但后来发现Top - down 递归就够了
// 然后发现所有的变量都会有一个相应的赋值
// 比如这种情况的Testcase就不存在["T2", ["T1=4", "T1 = 2 + T2"]]

#include <string>
#include <unordered_map>
#include <unordered_set>
#include <iostream>
#include <sstream>

using namespace std;

class Calculator {
public:
  Calculator(string target, vector<string>& exps) : expressions(exps), target(target) {}

  int dfs(string curr, unordered_map<string, string>& graph) {
    if (isdigit(curr[0])) {
        return stoi(curr);
    }

    return dfs(graph[curr], graph);
  }

  void trim(string& s) {
    int count = 0;
    int n = s.size();
    for (int i = 0; i < n; i++) {
        if (s[i] != ' ') {
            s[count++] = s[i];
        }
    }

    s = s.substr(0, count);
  }

  void constructGraph() {
    for (string& exp: expressions) {
        trim(exp);
        size_t equal = exp.find('=');
        string left = exp.substr(0, equal);
        string right = exp.substr(equal+1);
        graph[left] = right;
    }
  }

  void debugGraph() {
    for (auto i : graph) {
        cout << i.first << " " << i.second << endl;
    }
  }

  int cal() {
    constructGraph();
    debugGraph();
    return dfs(target, graph);
  }

  unordered_map<string, string> graph;
  vector<string> expressions;
  string target;
};

class CalculatorPart2 {
public:
    CalculatorPart2(string target, vector<string>& exps) : expressions(exps), target(target) {}

    string dfs(string curr, unordered_map<string, vector<string>>& graph, unordered_set<string>& visited) {
        if (isdigit(curr[0])) {
            return curr;
        }

        // Impossible to solve since we have no expression for this left hand string.
        if (!graph.count(curr)) {
            return "IMPOSSIBLE";
        }

        if (graph[curr].size() == 1 && isdigit(graph[curr][0][0])) {
            return graph[curr][0];
        }

        // Return computed cache
        // if (cache.count(curr)) {
        //     return cache[curr];
        // }

        // Part 3: detect cycle
        if (visited.count(curr)) {
            return "IMPOSSIBLE";
        }

        visited.insert(curr);

        int sum = 0;
        int sign = 1;
        for (auto i : graph[curr]) {
            if (i == "+") {
                sign = 1;
            } else if (i == "-") {
                sign = -1;
            } else {
                string s = dfs(i, graph, visited);
                // Part 3
                if (s == "IMPOSSIBLE") {
                    return s;
                }

                int val = stoi(s);
                sum += sign*val;
            }
        }

        return to_string(sum);
    }

    vector<string> split(string s) {
        vector<string> res;
        string current;

        for (char ch : s) {
            if (isdigit(ch) || isalpha(ch)) {
                current += ch;
            }
            else {
                if (!current.empty()) {
                    res.push_back(current);
                    current = "";
                }
                res.push_back(string(1, ch));
            }
        }

        if (!current.empty()) {
            res.push_back(current);
        }

        return res;
    }

    void trim(string& s) {
        int count = 0;
        int n = s.size();
        for (int i = 0; i < n; i++) {
            if (s[i] != ' ') {
                s[count++] = s[i];
            }
        }

        s = s.substr(0, count);
    }

    void constructGraph() {
        for (string& exp : expressions) {
            trim(exp);
            size_t equal = exp.find('=');
            string left = exp.substr(0, equal);
            string right = exp.substr(equal + 1);
            graph[left] = split(right);
        }
    }

    void debugGraph() {
        for (auto i : graph) {
            cout << "key: " <<  i.first << endl;
            for (auto j : i.second) {
                cout << j << " ";
            }
            cout << endl;
        }
    }

    string cal() {
        unordered_set<string> visited;
        constructGraph();
        // debugGraph();
        return dfs(target, graph, visited);
    }

    unordered_map<string, vector<string>> graph;
    vector<string> expressions;
    string target;
};


void test(vector<string> expressions, string target) {
    CalculatorPart2 expCalculator = CalculatorPart2(target, expressions);
    cout << expCalculator.cal() << endl;
}

int main() {
    test({ "T1 = 4", "T1 = 2 + T2" }, "T2"); // Impossible
    test({ "T1 = T2", "T2 = T1" }, "T2"); // Impossible
    test({ "T1 = T2", "T2 = T3", "T3 = 1+5-4" }, "T2"); // 1
    test({ "T1 = 1", "T2 = 2 + T4", "T3 = T1 - 4", "T4 = T1 + T3" }, "T2"); // 0
    test({ "T1 = 1", "T2 = 2 + T4", "T3 = T1 - 4", "T4 = T1 + T3" }, "T3"); // -3
    test({ "T1 = 1", "T2 = 2 + T4", "T3 = T1 - 4", "T4 = T1 + T3" }, "T4"); // -2
    test({ "X6 = 36",
 "X1 = X9",
 "X10 = X7",
 "X7 = X2",
 "X4 = X9",
 "X2 = X6",
 "X3 = X6",
 "X5 = X2",
 "X9 = X8",
 "X8 = 63" }, "X10"); // 36

    return 0;
}

// Entity parseUtil(ifstream& file) {
//     vector<string> res;
//     string line;

//     // Parse index
//     getline(file, line);
//     int idx;
//     istringstream iss_idx(line);
//     iss_idx >> idx;

//     // Part 3
//     if (seen.count(idx)) {
//         vector<string> res;
//         // return Entity(-1, -1, -1, res);
//         return Entity(-1, -1, -1);
//     }
//     seen.insert(idx);

//     // Parse x, y
//     getline(file, line);
//     char delim;
//     int x, y;
//     istringstream iss(line);
//     iss >> delim >> x >> delim >> y >> delim;

//     Entity e = Entity(x, y, idx);

//     // Parse board portion, if digit means it's next chunk of entity.
//     while (!isdigit(file.peek()) && getline(file, line) && !line.empty()) {
//         // res.push_back(line);
//         e.add(line);
//     }

//     // return Entity(x, y, idx, res);
//     return e;
// }```

Last updated