题目:
Your task is to design the basic function of Excel and implement the function of sum formula. Specifically, you need to implement the following functions:
Excel(int H, char W):
This is the constructor. The inputs represents the height and width of the Excel form. H is a positive integer, range from 1 to 26. It represents the height. W is a character range from 'A' to 'Z'. It represents that the width is the number of characters from 'A' to W. The Excel form content is represented by a height * width 2D integer array C
, it should be initialized to zero. You should assume that the first row of C
starts from 1, and the first column of C
starts from 'A'.
void Set(int row, char column, int val):
Change the value at C(row, column)
to be val.
int Get(int row, char column):
Return the value at C(row, column)
.
int Sum(int row, char column, List of Strings : numbers):
This function calculate and set the value at C(row, column)
, where the value should be the sum of cells represented by numbers
. This function return the sum result at C(row, column)
. This sum formula should exist until this cell is overlapped by another value or another sum formula.
numbers
is a list of strings that each string represent a cell or a range of cells. If the string represent a single cell, then it has the following format : ColRow
. For example, "F7" represents the cell at (7, F).
If the string represent a range of cells, then it has the following format : ColRow1:ColRow2
. The range will always be a rectangle, and ColRow1 represent the position of the top-left cell, and ColRow2 represents the position of the bottom-right cell.
Example 1:
Excel(3,"C"); // construct a 3*3 2D array with all zero. // A B C // 1 0 0 0 // 2 0 0 0 // 3 0 0 0 Set(1, "A", 2); // set C(1,"A") to be 2. // A B C // 1 2 0 0 // 2 0 0 0 // 3 0 0 0 Sum(3, "C", ["A1", "A1:B2"]); // set C(3,"C") to be the sum of value at C(1,"A") and the values sum of the rectangle range whose top-left cell is C(1,"A") and bottom-right cell is C(2,"B"). Return 4. // A B C // 1 2 0 0 // 2 0 0 0 // 3 0 0 4 Set(2, "B", 2); // set C(2,"B") to be 2. Note C(3, "C") should also be changed. // A B C // 1 2 0 0 // 2 0 2 0 // 3 0 0 6
Note:
- You could assume that there won't be any circular sum reference. For example, A1 = sum(B1) and B1 = sum(A1).
- The test cases are using double-quotes to represent a character.
- Please remember to RESET your class variables declared in class Excel, as static/class variables are persisted across multiple test cases. Please see here for more details.
思路:
这道题目也是hard模式的,而且难的“名副其实”。我自己写的代码肯定是很长效率很差的,这里翻译一段网上的代码及其相应的解释:
1)当一个cell改变时,所有与之相关的sum都需要做相应的update,所以我们记录一个fward,记录从一个cell到其所影响的所有sum的位置。而由于一个cell对另外一个cell的影响有可能是多次的(例如重合区域),所以我们用unordered_map<cell, unordered_map<cell, weight>>来表示。采用weight可以提高update的效率。
2)当一个cell的值被reset之后,或者被赋予一个新的range之后,所有原来影响它的cell都应该失效,所以我们还需要一个bward,用来建立影响某个cell的所有源cell。
为了方便,我们用row *26 + col来作为Excel表格的key,这样就可以将二维数组完全映射到一维上。
代码:
class Excel {
public:
Excel(int H, char W) {
exl = vector<vector<int>>(H + 1, vector<int>(W - 'A' + 1, 0));
fward.clear();
bward.clear();
}
void set(int r, char c, int v) {
int col = c - 'A';
int key = r * 26 + col;
update(r, col, v); // update its value and all the sum related
if (bward.count(key)) { // reset, so break all the forward links if existing
for (int k : bward[key]) {
fward[k].erase(key);
}
bward[key].clear();
}
}
int get(int r, char c) {
return exl[r][c - 'A'];
}
int sum(int r, char c, vector<string> strs) {
int col = c - 'A', key = r * 26 + col, ans = 0;
if (bward.count(key)) { // another reset for position (r, c)
for (int k:bward[key]) {
fward[k].erase(key);
}
bward[key].clear();
}
for (string str:strs) { // get the sum over multiple ranges
int p = str.find(':'), left, right, top, bot;
left = str[0] - 'A';
right = str[p + 1] - 'A';
if (p == -1) {
top = stoi(str.substr(1));
}
else {
top = stoi(str.substr(1, p - 1));
}
bot = stoi(str.substr(p + 2));
for (int i = top; i <= bot; ++i) {
for (int j = left; j <= right; ++j) {
ans += exl[i][j];
++fward[i * 26 + j][key];
bward[key].insert(i * 26 + j);
}
}
}
update(r, col, ans); // update this cell and all the sum related
return ans;
}
private:
void update(int r, int col, int v) {
// update a cell and all the sum related, using BFS
int prev = exl[r][col];
exl[r][col] = v;
queue<int> q; // q is keys for cells in next level
queue<int> update; // update is the increment for each cell
q.push(r * 26 + col);
update.push(v - prev);
while (!q.empty()) {
int key = q.front(), dif = update.front();
q.pop(), update.pop();
if(fward.count(key)) {
for (auto it = fward[key].begin(); it != fward[key].end(); ++it) {
int k = it->first;
q.push(k);
update.push(dif * (it->second));
exl[k / 26][k % 26] += dif * (it->second);
}
}
}
}
// The key of a cell is defined as 26 * row + col, which is int
vector<vector<int>> exl;
// fward links a cell to all the cells which use it for sum, and it may be used for
// multiple times due to overlap ranges, so another map is used for its weight
unordered_map<int, unordered_map<int, int>> fward;
// bward links a cell to all the cells that contribute to its sum. When reset its value,
// or reassign a new sum range to it, we need disconnect the forward link of those cells to it.
unordered_map<int, unordered_set<int>> bward;
};
/**
* Your Excel object will be instantiated and called as such:
* Excel obj = new Excel(H, W);
* obj.set(r,c,v);
* int param_2 = obj.get(r,c);
* int param_3 = obj.sum(r,c,strs);
*/