LeetCode 631. Design Excel Sum Formula
原题链接
困难
作者:
JasonSun
,
2020-02-19 15:31:32
,
所有人可见
,
阅读 1122
Algorithm (Design, Lazy Evaluation)
- Instead of evaluating each cell eagerly, we define each cell to be its evaluation functional.
- When we
set
a cell $c$ to be a value $v$, this evaluation functional is simply the constant $v$.
- When we
sum
a cell $c$ to be a sum of the a list of cell regions, the evaluation functional just changes to the sum of all the evaluation functionals in those regions.
- When we
get
a cell $c$, we return the result of the the evaluation functionals in $c$.
- To facilitate parsing of the input, we use an auxiliary tokenizer.
Code (Cpp17)
class basic_tokenizer {
private:
std::stringstream stream;
public:
basic_tokenizer(const std::string& str) : stream(str){};
public:
bool has_next() { return not stream.eof();}
char peek() { return stream.peek(); }
void consume() { next<char>(); };
public:
template <class T, typename std::enable_if_t<std::is_arithmetic_v<T>
or std::is_same_v<string, T>>* = nullptr>
T next() {
auto data = T{};
stream >> data;
return data;
}
};
struct cell_t {
std::optional<std::function<int(void)>> eval;
};
class Excel {
private:
cell_t cells[128][128];
using tokenizer = basic_tokenizer;
int sum_one(const std::string& str) {
auto tokens = tokenizer(str);
const auto c1 = tokens.next<char>();
const auto r1 = tokens.next<int>();
if (not tokens.has_next())
return get(r1, c1);
else if (tokens.peek() == ':') {
tokens.consume();
const auto c2 = tokens.next<char>();
const auto r2 = tokens.next<int>();
const auto res = [&](int acc = 0) {
for (int r = r1; r <= r2; ++r)
for (int c = c1; c <= c2; ++c)
acc += get(r, c);
return acc;
}();
return res;
}
throw std::domain_error("");
}
public:
Excel(int H, char W) : cells{} {
for (int r = 0; r <= H; r++)
for (char c = 'A'; c <= W; ++c)
cells[r][c].eval = [] { return 0; };
}
void set(int r, char c, int v) {
cells[r][c].eval = [v] { return v; };
}
int get(int r, char c) {
return std::invoke(cells[r][c].eval.value());
}
int sum(int r, char c, vector<string> strs) {
cells[r][c].eval = [this, strs](int acc = 0) {
for (const auto& s : strs)
acc += sum_one(s);
return acc;
};
return get(r, c);
}
};