OAmaster
— / 2已做

You are given symbol definitions in the form name=expression. An expression may contain integer constants, references to previously defined or later defined symbols, and the binary operators +, -, *, and /. Evaluate the final integer value of every symbol. Return the results in the same order as the input definitions, formatted as "name=value". If the dependency graph contains a cycle, return a single-element array ["CYCLE"] instead of partial results. Function Description Complete the function evaluateExpressionMap in the editor below. evaluateExpressionMap has the following parameter:

  • String[] definitions: the symbol definitions Returns String[]: evaluated symbol assignments in input order, or ["CYCLE"] if a cycle exists.

Constraints

  • 1 ≤ definitions.length ≤ 10⁵
  • Expressions use integer arithmetic and may reference other symbols.
  • Use cycle detection to avoid infinite recursion.

Example 1

Input:

definitions = ["a=1", "b=a+2", "c=b*3"]

Output:

["a=1", "b=3", "c=9"]

Explanation: Each symbol depends only on earlier evaluated values, so the map resolves cleanly.

Example 2

Input:

definitions = ["a=b+1", "b=a+1"]

Output:

["CYCLE"]

Explanation: The definitions form a cycle, so the special cycle marker is returned.

解法

把每个定义解析成「名字 → 表达式 token 序列」,然后对每个 name 做带 visiting 集合的 DFS:递归求值变量,求值过程中再次进入同一个 name 就说明有环,立即返回 CYCLE。表达式求值用经典「分两阶段:先处理 *//,再处理 +/-」或调度场算法。时间 O(N·E),E 是平均表达式长度。

from typing import List
import re

def evaluateExpressionMap(definitions: List[str]) -> List[str]:
    defs: dict[str, str] = {}
    order: List[str] = []
    for d in definitions:
        name, expr = d.split("=", 1)
        defs[name.strip()] = expr.strip()
        order.append(name.strip())

    cache: dict[str, int] = {}
    visiting: set[str] = set()
    has_cycle = [False]

    def evaluate(expr: str) -> int:
        tokens = re.findall(r"\d+|[A-Za-z_][A-Za-z_0-9]*|[+\-*/()]", expr)
        # Shunting-yard to RPN
        prec = {"+": 1, "-": 1, "*": 2, "/": 2}
        out: List[str] = []
        ops: List[str] = []
        for t in tokens:
            if t.isdigit() or (t[0].isalpha() or t[0] == "_"):
                out.append(t)
            elif t in prec:
                while ops and ops[-1] in prec and prec[ops[-1]] >= prec[t]:
                    out.append(ops.pop())
                ops.append(t)
        while ops:
            out.append(ops.pop())
        stack: List[int] = []
        for t in out:
            if t in prec:
                b = stack.pop(); a = stack.pop()
                if t == "+": stack.append(a + b)
                elif t == "-": stack.append(a - b)
                elif t == "*": stack.append(a * b)
                else: stack.append(a // b if a * b >= 0 else -((-a) // b) if a < 0 else a // b)
            elif t.isdigit():
                stack.append(int(t))
            else:
                stack.append(resolve(t))
                if has_cycle[0]:
                    return 0
        return stack[0]

    def resolve(name: str) -> int:
        if has_cycle[0]:
            return 0
        if name in cache:
            return cache[name]
        if name in visiting:
            has_cycle[0] = True
            return 0
        visiting.add(name)
        v = evaluate(defs[name])
        visiting.remove(name)
        cache[name] = v
        return v

    results: List[str] = []
    for name in order:
        v = resolve(name)
        if has_cycle[0]:
            return ["CYCLE"]
        results.append(f"{name}={v}")
    return results
import java.util.*;
import java.util.regex.*;

class Solution {
    private Map<String, String> defs = new HashMap<>();
    private Map<String, Integer> cache = new HashMap<>();
    private Set<String> visiting = new HashSet<>();
    private boolean hasCycle = false;

    String[] evaluateExpressionMap(String[] definitions) {
        List<String> order = new ArrayList<>();
        for (String d : definitions) {
            int eq = d.indexOf('=');
            String name = d.substring(0, eq).trim();
            defs.put(name, d.substring(eq + 1).trim());
            order.add(name);
        }
        List<String> results = new ArrayList<>();
        for (String name : order) {
            int v = resolve(name);
            if (hasCycle) return new String[]{"CYCLE"};
            results.add(name + "=" + v);
        }
        return results.toArray(new String[0]);
    }

    private int resolve(String name) {
        if (hasCycle) return 0;
        if (cache.containsKey(name)) return cache.get(name);
        if (visiting.contains(name)) { hasCycle = true; return 0; }
        visiting.add(name);
        int v = evaluate(defs.get(name));
        visiting.remove(name);
        cache.put(name, v);
        return v;
    }

    private int evaluate(String expr) {
        List<String> tokens = new ArrayList<>();
        Matcher m = Pattern.compile("\\d+|[A-Za-z_][A-Za-z_0-9]*|[+\\-*/()]").matcher(expr);
        while (m.find()) tokens.add(m.group());
        Map<String, Integer> prec = Map.of("+", 1, "-", 1, "*", 2, "/", 2);
        List<String> out = new ArrayList<>();
        Deque<String> ops = new ArrayDeque<>();
        for (String t : tokens) {
            if (t.matches("\\d+") || Character.isLetter(t.charAt(0)) || t.charAt(0) == '_') out.add(t);
            else if (prec.containsKey(t)) {
                while (!ops.isEmpty() && prec.containsKey(ops.peek()) && prec.get(ops.peek()) >= prec.get(t)) out.add(ops.pop());
                ops.push(t);
            }
        }
        while (!ops.isEmpty()) out.add(ops.pop());
        Deque<Integer> stack = new ArrayDeque<>();
        for (String t : out) {
            if (prec.containsKey(t)) {
                int b = stack.pop(), a = stack.pop();
                switch (t) {
                    case "+": stack.push(a + b); break;
                    case "-": stack.push(a - b); break;
                    case "*": stack.push(a * b); break;
                    default: stack.push(a / b);
                }
            } else if (t.matches("\\d+")) stack.push(Integer.parseInt(t));
            else { stack.push(resolve(t)); if (hasCycle) return 0; }
        }
        return stack.peek();
    }
}
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <stack>
#include <regex>

class Solution {
    std::unordered_map<std::string, std::string> defs;
    std::unordered_map<std::string, int> cache;
    std::unordered_set<std::string> visiting;
    bool hasCycle = false;

    int evaluate(const std::string& expr) {
        std::vector<std::string> tokens;
        std::regex re("\\d+|[A-Za-z_][A-Za-z_0-9]*|[+\\-*/()]");
        for (auto it = std::sregex_iterator(expr.begin(), expr.end(), re); it != std::sregex_iterator(); ++it)
            tokens.push_back(it->str());
        std::unordered_map<std::string, int> prec{{"+", 1}, {"-", 1}, {"*", 2}, {"/", 2}};
        std::vector<std::string> out;
        std::stack<std::string> ops;
        for (auto& t : tokens) {
            if (isdigit(t[0]) || isalpha(t[0]) || t[0] == '_') out.push_back(t);
            else if (prec.count(t)) {
                while (!ops.empty() && prec.count(ops.top()) && prec[ops.top()] >= prec[t]) { out.push_back(ops.top()); ops.pop(); }
                ops.push(t);
            }
        }
        while (!ops.empty()) { out.push_back(ops.top()); ops.pop(); }
        std::stack<int> st;
        for (auto& t : out) {
            if (prec.count(t)) {
                int b = st.top(); st.pop();
                int a = st.top(); st.pop();
                if (t == "+") st.push(a + b);
                else if (t == "-") st.push(a - b);
                else if (t == "*") st.push(a * b);
                else st.push(a / b);
            } else if (isdigit(t[0])) st.push(std::stoi(t));
            else { st.push(resolve(t)); if (hasCycle) return 0; }
        }
        return st.top();
    }

    int resolve(const std::string& name) {
        if (hasCycle) return 0;
        auto it = cache.find(name);
        if (it != cache.end()) return it->second;
        if (visiting.count(name)) { hasCycle = true; return 0; }
        visiting.insert(name);
        int v = evaluate(defs[name]);
        visiting.erase(name);
        cache[name] = v;
        return v;
    }

public:
    std::vector<std::string> evaluateExpressionMap(std::vector<std::string>& definitions) {
        std::vector<std::string> order;
        for (auto& d : definitions) {
            auto eq = d.find('=');
            std::string name = d.substr(0, eq);
            defs[name] = d.substr(eq + 1);
            order.push_back(name);
        }
        std::vector<std::string> results;
        for (auto& name : order) {
            int v = resolve(name);
            if (hasCycle) return {"CYCLE"};
            results.push_back(name + "=" + std::to_string(v));
        }
        return results;
    }
};

Complete the function below. The function receives the full standard input as a single string and returns the exact standard output lines for a small spreadsheet engine. Implement a spreadsheet with cell labels such as A1 and B10. The spreadsheet supports setting cells to integers or formulas, retrieving evaluated values, and detecting cycles. A formula is a +-separated expression containing non-negative integer literals and/or cell labels. Operators other than + are not required. Supported commands:

  • SET label value: set label to an integer or formula. Return OK if the assignment does not create a dependency cycle; otherwise leave the spreadsheet unchanged and return ERROR.
  • GET label: return the evaluated integer value of label. Return ERROR if the cell is unset or cannot be evaluated. Cell dependencies are evaluated lazily or eagerly as you choose, but GET must always reflect the latest committed cell values. Function Description Complete solveSpreadsheetFormulaEvaluator. It has one parameter, String input, containing newline-separated commands. Return the stdout payload as an array of lines, without trailing newline characters.

Constraints

Cell labels consist of uppercase letters followed by digits, such as A1 or B10. Formula expressions only need to support addition with +. Assignments that introduce a cycle must be rejected.

Pro解法 · 三语代码 · 复杂度分析
边界讨论 + 面试官追问 · $98 / 一年解锁
Pro 会员

解锁全部 1 道题的解法

题面你已经看到了 — 解法 + 三语代码 + 复杂度推导 + 边界讨论, Pro 解锁.

Pro 解锁全部
  • 📚1000+ 道真实北美 OA, Python / Java / C++ 三语题解
  • 📊个人 dashboard + 进度可视化 + 14 天活跃图
  • 📝题目笔记跨设备同步 + 个人复盘库
  • 🔓随时取消下次续费, Stripe Customer Portal 自助管理
$12/月($98/年, 一次付清省 32%)

≈ 北美 SWE 工资 10 分钟 · LeetCode Premium $35/月 的 23%