Skip to content

Commit 11bf594

Browse files
committed
完成「第 1 ~ 1000 题」的题目解析
1 parent 2d5f055 commit 11bf594

4 files changed

Lines changed: 200 additions & 1 deletion

File tree

docs/00_preface/00_05_solutions_list.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# LeetCode 题解(已完成 1301 道)
1+
# LeetCode 题解(已完成 1302 道)
22

33
### 第 1 ~ 99 题
44

@@ -620,6 +620,7 @@
620620
| [0628. 三个数的最大乘积](https://leetcode.cn/problems/maximum-product-of-three-numbers/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/maximum-product-of-three-numbers.md) | 数组、数学、排序 | 简单 |
621621
| [0629. K 个逆序对数组](https://leetcode.cn/problems/k-inverse-pairs-array/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/k-inverse-pairs-array.md) | 动态规划 | 困难 |
622622
| [0630. 课程表 III](https://leetcode.cn/problems/course-schedule-iii/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/course-schedule-iii.md) | 贪心、数组、排序、堆(优先队列) | 困难 |
623+
| [0631. 设计 Excel 求和公式](https://leetcode.cn/problems/design-excel-sum-formula/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/design-excel-sum-formula.md) | 图、设计、拓扑排序、数组、哈希表、字符串、矩阵 | 困难 |
623624
| [0632. 最小区间](https://leetcode.cn/problems/smallest-range-covering-elements-from-k-lists/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/smallest-range-covering-elements-from-k-lists.md) | 贪心、数组、哈希表、排序、滑动窗口、堆(优先队列) | 困难 |
624625
| [0633. 平方数之和](https://leetcode.cn/problems/sum-of-square-numbers/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/sum-of-square-numbers.md) | 数学、双指针、二分查找 | 中等 |
625626
| [0634. 寻找数组的错位排列](https://leetcode.cn/problems/find-the-derangement-of-an-array/) | [题解](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/find-the-derangement-of-an-array.md) | 数学、动态规划、组合数学 | 中等 |

docs/others/update_time.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 2026-01
22

3+
- 2026-01-16 **完成「第 1 ~ 1000 题」的题目解析**
4+
- 2026-01-15 补充第 600 ~ 699 题的题目解析(增加 3 道题)
35
- 2026-01-12 补充第 600 ~ 699 题的题目解析(增加 11 道题)
46
- 2026-01-11 补充第 001 ~ 599 题的题目解析(增加 35 道题)
57
- 2026-01-09 补充第 900 ~ 999 题的题目解析(增加 69 道题)
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# [0631. 设计 Excel 求和公式](https://leetcode.cn/problems/design-excel-sum-formula/)
2+
3+
- 标签:图、设计、拓扑排序、数组、哈希表、字符串、矩阵
4+
- 难度:困难
5+
6+
## 题目链接
7+
8+
- [0631. 设计 Excel 求和公式 - 力扣](https://leetcode.cn/problems/design-excel-sum-formula/)
9+
10+
## 题目大意
11+
12+
**描述**
13+
14+
请你设计 Excel 中的基本功能,并实现求和公式。
15+
16+
**要求**
17+
18+
实现 Excel 类:
19+
20+
- `Excel(int height, char width)`:用高度 $height$ 和宽度 $width$ 初始化对象。该表格是一个大小为 $height \times width$ 的整数矩阵 $mat$,其中行下标范围是 $[1, height]$,列下标范围是 $['A', width]$。初始情况下,所有的值都应该为零。
21+
- `void set(int row, char column, int val)`:将 $mat[row][column]$ 的值更改为 $val$。
22+
- `int get(int row, char column)`:返回 $mat[row][column]$ 的值。
23+
- `int sum(int row, char column, List<String> numbers)`:将 $mat[row][column]$ 的值设为由 $numbers$ 表示的单元格的和,并返回 $mat[row][column]$ 的值。此求和公式应该 **长期作用于** 该单元格,直到该单元格被另一个值或另一个求和公式覆盖。其中,$numbers[i]$ 的格式可以为:
24+
- `"ColRow"`:表示某个单元格。例如,`"F7"` 表示单元格 $mat[7]['F']$。
25+
- `"ColRow1:ColRow2"`:表示一组单元格。该范围将始终为一个矩形,其中 `"ColRow1"` 表示左上角单元格的位置,`"ColRow2"` 表示右下角单元格的位置。例如,`"B3:F7"` 表示 $3 \le i \le 7$ 和 $'B' \le j \le 'F'$ 的单元格 $mat[i][j]$。
26+
27+
**说明**
28+
29+
- 注意:可以假设不会出现循环求和引用。例如,$mat[1]['A'] == sum(1, "B")$,且 $mat[1]['B'] == sum(1, "A")$。
30+
- $1 \le height \le 26$。
31+
- $'A' \le width \le 'Z'$。
32+
- $1 \le row \le height$。
33+
- $'A' \le column \le width$。
34+
- $-10^3 \le val \le 10^3$。
35+
- $1 \le numbers.length \le 5$。
36+
- $numbers[i]$ 的格式为 `"ColRow"``"ColRow1:ColRow2"`
37+
- 最多会对 `set``get``sum` 进行 $10^3$ 次调用。
38+
39+
**示例**
40+
41+
- 示例 1:
42+
43+
```python
44+
输入:
45+
["Excel", "set", "sum", "set", "get"]
46+
[[3, "C"], [1, "A", 2], [3, "C", ["A1", "A1:B2"]], [2, "B", 2], [3, "C"]]
47+
输出:
48+
[null, null, 4, null, 6]
49+
50+
解释:
51+
执行以下操作:
52+
Excel excel = new Excel(3, "C");
53+
// 构造一个 3 * 3 的二维数组,所有值初始化为零。
54+
// A B C
55+
// 1 0 0 0
56+
// 2 0 0 0
57+
// 3 0 0 0
58+
excel.set(1, "A", 2);
59+
// 将 mat[1]["A"] 设置为 2
60+
// A B C
61+
// 1 2 0 0
62+
// 2 0 0 0
63+
// 3 0 0 0
64+
excel.sum(3, "C", ["A1", "A1:B2"]); // 返回 4
65+
// 将 mat[3]["C"] 设置为 mat[1]["A"] 的值与矩形范围的单元格和的和,该范围的左上角单元格位置为 mat[1]["A"],右下角单元格位置为 mat[2]["B"]。
66+
// A B C
67+
// 1 2 0 0
68+
// 2 0 0 0
69+
// 3 0 0 4
70+
excel.set(2, "B", 2);
71+
// 将 mat[2]["B"] 设置为 2 。注意 mat[3]["C"] 也应该更改。
72+
// A B C
73+
// 1 2 0 0
74+
// 2 0 2 0
75+
// 3 0 0 6
76+
excel.get(3, "C"); // 返回 6
77+
```
78+
79+
## 解题思路
80+
81+
### 思路 1:哈希表 + 图
82+
83+
这道题目要求设计一个 Excel 表格,支持设置单元格值、获取单元格值和设置求和公式。关键在于求和公式需要 **长期作用**,即当依赖的单元格值改变时,公式单元格的值也要自动更新。
84+
85+
**核心思路**
86+
87+
- 使用哈希表存储每个单元格的值。
88+
- 使用图结构记录单元格之间的依赖关系:如果单元格 $A$ 的值依赖于单元格 $B$,则 $B \to A$ 有一条边。
89+
- 当某个单元格的值改变时,需要递归更新所有依赖它的单元格。
90+
91+
**算法步骤**
92+
93+
1. **初始化**:创建哈希表存储单元格值,创建图存储依赖关系。
94+
2. **set 操作**:设置单元格值,清除该单元格的依赖关系,递归更新依赖它的单元格。
95+
3. **get 操作**:直接返回单元格的值。
96+
4. **sum 操作**:解析 $numbers$,计算和,设置单元格值,建立依赖关系。
97+
98+
### 思路 1:代码
99+
100+
```python
101+
class Excel:
102+
103+
def __init__(self, height: int, width: str):
104+
self.height = height
105+
self.width = ord(width) - ord('A') + 1
106+
# formulas[r][c] = (cells_dict, val)
107+
# cells_dict: 依赖的单元格及其计数,val: 当前值
108+
self.formulas = [[None] * self.width for _ in range(height)]
109+
110+
def get(self, row: int, column: str) -> int:
111+
r, c = row - 1, ord(column) - ord('A')
112+
if self.formulas[r][c] is None:
113+
return 0
114+
return self.formulas[r][c][1]
115+
116+
def set(self, row: int, column: str, val: int) -> None:
117+
r, c = row - 1, ord(column) - ord('A')
118+
# 设置为纯值,清空依赖
119+
self.formulas[r][c] = ({}, val)
120+
# 拓扑排序更新依赖此单元格的所有单元格
121+
stack = []
122+
self._topological_sort(r, c, stack, set())
123+
self._execute_stack(stack)
124+
125+
def sum(self, row: int, column: str, numbers: List[str]) -> int:
126+
r, c = row - 1, ord(column) - ord('A')
127+
cells = self._convert(numbers)
128+
summ = self._calculate_sum(r, c, cells)
129+
self.formulas[r][c] = (cells, summ)
130+
# 拓扑排序更新依赖此单元格的所有单元格
131+
stack = []
132+
self._topological_sort(r, c, stack, set())
133+
self._execute_stack(stack)
134+
return summ
135+
136+
def _convert(self, strs: List[str]) -> dict:
137+
"""将公式字符串转换为单元格计数字典"""
138+
res = {}
139+
for st in strs:
140+
if ':' not in st:
141+
res[st] = res.get(st, 0) + 1
142+
else:
143+
parts = st.split(':')
144+
si, ei = int(parts[0][1:]), int(parts[1][1:])
145+
sj, ej = parts[0][0], parts[1][0]
146+
for i in range(si, ei + 1):
147+
for j in range(ord(sj), ord(ej) + 1):
148+
key = chr(j) + str(i)
149+
res[key] = res.get(key, 0) + 1
150+
return res
151+
152+
def _topological_sort(self, r: int, c: int, stack: list, visited: set) -> None:
153+
"""拓扑排序:找出所有依赖 (r,c) 的单元格"""
154+
key = chr(ord('A') + c) + str(r + 1)
155+
for i in range(len(self.formulas)):
156+
for j in range(len(self.formulas[0])):
157+
if self.formulas[i][j] is not None and key in self.formulas[i][j][0]:
158+
if (i, j) not in visited:
159+
self._topological_sort(i, j, stack, visited)
160+
if (r, c) not in visited:
161+
visited.add((r, c))
162+
stack.append((r, c))
163+
164+
def _execute_stack(self, stack: list) -> None:
165+
"""按拓扑顺序更新单元格"""
166+
while stack:
167+
r, c = stack.pop()
168+
if self.formulas[r][c] is not None and self.formulas[r][c][0]:
169+
self._calculate_sum(r, c, self.formulas[r][c][0])
170+
171+
def _calculate_sum(self, r: int, c: int, cells: dict) -> int:
172+
"""计算单元格的和"""
173+
total = 0
174+
for s, cnt in cells.items():
175+
x, y = int(s[1:]) - 1, ord(s[0]) - ord('A')
176+
val = self.formulas[x][y][1] if self.formulas[x][y] else 0
177+
total += val * cnt
178+
self.formulas[r][c] = (cells, total)
179+
return total
180+
181+
182+
# Your Excel object will be instantiated and called as such:
183+
# obj = Excel(height, width)
184+
# obj.set(row,column,val)
185+
# param_2 = obj.get(row,column)
186+
# param_3 = obj.sum(row,column,numbers)
187+
```
188+
189+
### 思路 1:复杂度分析
190+
191+
- **时间复杂度**
192+
- $set$ 操作:$O(d)$,其中 $d$ 是依赖此单元格的单元格数量,需要更新所有依赖的单元格。
193+
- $get$ 操作:$O(1)$,直接返回缓存的值。
194+
- $sum$ 操作:$O(k + d)$,其中 $k$ 是公式中依赖的单元格数量,$d$ 是依赖此单元格的单元格数量。需要计算所有依赖的单元格,并更新依赖此单元格的其他单元格。
195+
- **空间复杂度**:$O(n + m)$,其中 $n$ 是单元格的数量,$m$ 是依赖关系的数量。

docs/solutions/0600-0699/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- [0628. 三个数的最大乘积](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/maximum-product-of-three-numbers.md)
1717
- [0629. K 个逆序对数组](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/k-inverse-pairs-array.md)
1818
- [0630. 课程表 III](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/course-schedule-iii.md)
19+
- [0631. 设计 Excel 求和公式](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/design-excel-sum-formula.md)
1920
- [0632. 最小区间](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/smallest-range-covering-elements-from-k-lists.md)
2021
- [0633. 平方数之和](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/sum-of-square-numbers.md)
2122
- [0634. 寻找数组的错位排列](https://github.com/ITCharge/AlgoNote/tree/main/docs/solutions/0600-0699/find-the-derangement-of-an-array.md)

0 commit comments

Comments
 (0)