Skip to content

Commit f5dee62

Browse files
committed
2026-01-03 补充第 700 ~ 799 题的题目解析(增加 27 道题)
1 parent c6ae51f commit f5dee62

30 files changed

+2995
-2
lines changed

docs/00_preface/00_05_solutions_list.md

Lines changed: 28 additions & 1 deletion
Large diffs are not rendered by default.

docs/others/update_time.md

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

3-
- 2026-01-01 补充第 500 ~ 599 题的题目解析(增加 34 道题)
3+
- 2026-01-03 补充第 700 ~ 799 题的题目解析(增加 27 道题)
44
- 2026-01-02 补充第 600 ~ 699 题的题目解析(增加 34 道题)
5+
- 2026-01-01 补充第 500 ~ 599 题的题目解析(增加 34 道题)
56

67
## 2025-10
78

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# [0717. 1 比特与 2 比特字符](https://leetcode.cn/problems/1-bit-and-2-bit-characters/)
2+
3+
- 标签:数组
4+
- 难度:简单
5+
6+
## 题目链接
7+
8+
- [0717. 1 比特与 2 比特字符 - 力扣](https://leetcode.cn/problems/1-bit-and-2-bit-characters/)
9+
10+
## 题目大意
11+
12+
**描述**
13+
14+
有两种特殊字符:
15+
16+
- 第一种字符可以用一比特 $0$ 表示
17+
- 第二种字符可以用两比特($10$ 或 $11$)表示
18+
19+
给定一个以 $0$ 结尾的二进制数组 $bits$。
20+
21+
**要求**
22+
23+
如果最后一个字符必须是一个一比特字符,则返回 true。
24+
25+
**说明**
26+
27+
- $1 \le bits.length \le 10^{3}$。
28+
- $bits[i]$ 为 $0$ 或 $1$。
29+
30+
**示例**
31+
32+
- 示例 1:
33+
34+
```python
35+
输入: bits = [1, 0, 0]
36+
输出: true
37+
解释: 唯一的解码方式是将其解析为一个两比特字符和一个一比特字符。
38+
所以最后一个字符是一比特字符。
39+
```
40+
41+
- 示例 2:
42+
43+
```python
44+
输入:bits = [1,1,1,0]
45+
输出:false
46+
解释:唯一的解码方式是将其解析为两比特字符和两比特字符。
47+
所以最后一个字符不是一比特字符。
48+
```
49+
50+
## 解题思路
51+
52+
### 思路 1:贪心算法
53+
54+
这道题的关键在于理解字符的编码规则:
55+
56+
- 一比特字符:`0`
57+
- 两比特字符:`10``11`
58+
59+
由于数组以 `0` 结尾,我们需要判断这个 `0` 是作为一比特字符单独存在,还是作为两比特字符的一部分。
60+
61+
**解题步骤**
62+
63+
1. 从数组开头开始遍历,使用指针 $i$ 记录当前位置。
64+
2. 如果 $bits[i] = 1$,说明当前是两比特字符,跳过两位($i$ 增加 $2$)。
65+
3. 如果 $bits[i] = 0$,说明当前是一比特字符,跳过一位($i$ 增加 $1$)。
66+
4. 当 $i$ 到达倒数第二个位置时停止遍历。
67+
5. 如果 $i$ 正好等于 $n - 1$(最后一个位置),说明最后一个 `0` 是一比特字符,返回 `True`
68+
6. 如果 $i$ 超过了 $n - 1$,说明最后一个 `0` 是两比特字符的一部分,返回 `False`
69+
70+
### 思路 1:代码
71+
72+
```python
73+
class Solution:
74+
def isOneBitCharacter(self, bits: List[int]) -> bool:
75+
n = len(bits)
76+
i = 0
77+
78+
# 遍历到倒数第二个位置
79+
while i < n - 1:
80+
if bits[i] == 1: # 两比特字符
81+
i += 2
82+
else: # 一比特字符
83+
i += 1
84+
85+
# 如果 i 正好等于 n - 1,说明最后一个 0 是一比特字符
86+
return i == n - 1
87+
```
88+
89+
### 思路 1:复杂度分析
90+
91+
- **时间复杂度**:$O(n)$,其中 $n$ 是数组 $bits$ 的长度。需要遍历整个数组一次。
92+
- **空间复杂度**:$O(1)$。只使用了常数个额外变量。
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# [0721. 账户合并](https://leetcode.cn/problems/accounts-merge/)
2+
3+
- 标签:深度优先搜索、广度优先搜索、并查集、数组、哈希表、字符串、排序
4+
- 难度:中等
5+
6+
## 题目链接
7+
8+
- [0721. 账户合并 - 力扣](https://leetcode.cn/problems/accounts-merge/)
9+
10+
## 题目大意
11+
12+
**描述**
13+
14+
给定一个列表 $accounts$,每个元素 $accounts[i]$ 是一个字符串列表,其中第一个元素 $accounts[i][0]$ 是名称($name$),其余元素是 $emails$ 表示该账户的邮箱地址。
15+
16+
现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。
17+
18+
**要求**
19+
20+
合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是按字符 ASCII 顺序排列的邮箱地址。账户本身可以以任意顺序返回。
21+
22+
**说明**
23+
24+
- $1 \le accounts.length \le 10^{3}$。
25+
- $2 \le accounts[i].length \le 10$。
26+
- $1 \le accounts[i][j].length \le 30$。
27+
- $accounts[i][0]$ 由英文字母组成。
28+
- $accounts[i][j] (for j \gt 0)$ 是有效的邮箱地址。
29+
30+
**示例**
31+
32+
- 示例 1:
33+
34+
```python
35+
输入:accounts = [["John", "[email protected]", "[email protected]"], ["John", "[email protected]"], ["John", "[email protected]", "[email protected]"], ["Mary", "[email protected]"]]
36+
37+
解释:
38+
第一个和第三个 John 是同一个人,因为他们有共同的邮箱地址 "[email protected]"
39+
第二个 John 和 Mary 是不同的人,因为他们的邮箱地址没有被其他帐户使用。
40+
可以以任何顺序返回这些列表,例如答案 [['Mary''[email protected]'],['John''[email protected]'],
41+
['John''[email protected]''[email protected]''[email protected]']] 也是正确的。
42+
```
43+
44+
- 示例 2:
45+
46+
```python
47+
48+
49+
```
50+
51+
## 解题思路
52+
53+
### 思路 1:并查集
54+
55+
这道题的核心是将具有相同邮箱的账户合并在一起。可以使用并查集来解决。
56+
57+
**解题步骤**
58+
59+
1. 将每个邮箱看作一个节点,如果两个邮箱属于同一个账户,就将它们连接起来。
60+
2. 使用哈希表 $email\_to\_id$ 记录每个邮箱对应的账户索引。
61+
3. 使用并查集将属于同一个人的邮箱合并到同一个集合中。
62+
4. 遍历所有账户,对于每个账户中的邮箱:
63+
- 如果邮箱第一次出现,记录其账户索引。
64+
- 如果邮箱已经出现过,将当前账户与之前的账户合并。
65+
5. 最后,将同一集合中的所有邮箱归类到一起,并按字典序排序。
66+
67+
### 思路 1:代码
68+
69+
```python
70+
class Solution:
71+
def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
72+
# 并查集
73+
parent = {}
74+
75+
def find(x):
76+
if x not in parent:
77+
parent[x] = x
78+
if parent[x] != x:
79+
parent[x] = find(parent[x])
80+
return parent[x]
81+
82+
def union(x, y):
83+
root_x = find(x)
84+
root_y = find(y)
85+
if root_x != root_y:
86+
parent[root_x] = root_y
87+
88+
# 邮箱到账户索引的映射
89+
email_to_id = {}
90+
# 邮箱到姓名的映射
91+
email_to_name = {}
92+
93+
# 遍历所有账户,建立邮箱之间的连接
94+
for account in accounts:
95+
name = account[0]
96+
for i in range(1, len(account)):
97+
email = account[i]
98+
email_to_name[email] = name
99+
100+
if email not in email_to_id:
101+
email_to_id[email] = email
102+
103+
# 将当前账户的所有邮箱合并到第一个邮箱的集合中
104+
union(account[1], email)
105+
106+
# 将同一集合的邮箱归类
107+
merged = {}
108+
for email in email_to_id:
109+
root = find(email)
110+
if root not in merged:
111+
merged[root] = []
112+
merged[root].append(email)
113+
114+
# 构建结果
115+
result = []
116+
for emails in merged.values():
117+
name = email_to_name[emails[0]]
118+
result.append([name] + sorted(emails))
119+
120+
return result
121+
```
122+
123+
### 思路 1:复杂度分析
124+
125+
- **时间复杂度**:$O(n \log n)$,其中 $n$ 是所有邮箱的总数。并查集操作的时间复杂度接近 $O(1)$,主要时间消耗在排序上。
126+
- **空间复杂度**:$O(n)$。需要存储并查集、哈希表等数据结构。
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# [0799. 香槟塔](https://leetcode.cn/problems/champagne-tower/)
2+
3+
- 标签:动态规划
4+
- 难度:中等
5+
6+
## 题目链接
7+
8+
- [0799. 香槟塔 - 力扣](https://leetcode.cn/problems/champagne-tower/)
9+
10+
## 题目大意
11+
12+
**描述**
13+
14+
我们把玻璃杯摆成金字塔的形状,其中第一层有 $1$ 个玻璃杯,第二层有 $2$ 个,依次类推到第 $100$ 层,每个玻璃杯将盛有香槟。
15+
16+
从顶层的第一个玻璃杯开始倾倒一些香槟,当顶层的杯子满了,任何溢出的香槟都会立刻等流量的流向左右两侧的玻璃杯。当左右两边的杯子也满了,就会等流量的流向它们左右两边的杯子,依次类推。(当最底层的玻璃杯满了,香槟会流到地板上)
17+
18+
例如,在倾倒一杯香槟后,最顶层的玻璃杯满了。倾倒了两杯香槟后,第二层的两个玻璃杯各自盛放一半的香槟。在倒三杯香槟后,第二层的香槟满了 - 此时总共有三个满的玻璃杯。在倒第四杯后,第三层中间的玻璃杯盛放了一半的香槟,他两边的玻璃杯各自盛放了四分之一的香槟,如下图所示。
19+
20+
![](https://s3-lc-upload.s3.amazonaws.com/uploads/2018/03/09/tower.png)
21+
22+
**要求**
23+
24+
现在当倾倒了非负整数杯香槟后,返回第 $i$ 行 $j$ 个玻璃杯所盛放的香槟占玻璃杯容积的比例( $i$ 和 $j$ 都从 $0$ 开始)。
25+
26+
**说明**
27+
28+
- $0 \le poured \le 10^{9}$。
29+
- $0 \le query\_glass \le query\_row \lt 10^{3}$。
30+
31+
**示例**
32+
33+
- 示例 1:
34+
35+
```python
36+
示例 1:
37+
输入: poured(倾倒香槟总杯数) = 1, query_glass(杯子的位置数) = 1, query_row(行数) = 1
38+
输出: 0.00000
39+
解释: 我们在顶层(下标是(00))倒了一杯香槟后,没有溢出,因此所有在顶层以下的玻璃杯都是空的。
40+
```
41+
42+
- 示例 2:
43+
44+
```python
45+
输入: poured(倾倒香槟总杯数) = 2, query_glass(杯子的位置数) = 1, query_row(行数) = 1
46+
输出: 0.50000
47+
解释: 我们在顶层(下标是(00)倒了两杯香槟后,有一杯量的香槟将从顶层溢出,位于(10)的玻璃杯和(11)的玻璃杯平分了这一杯香槟,所以每个玻璃杯有一半的香槟。
48+
```
49+
50+
## 解题思路
51+
52+
### 思路 1:动态规划 + 模拟
53+
54+
这道题可以使用动态规划来模拟香槟倾倒的过程。
55+
56+
**解题步骤**
57+
58+
1. 定义 $dp[i][j]$ 表示第 $i$ 行第 $j$ 个杯子中的香槟量(可能超过 $1$)。
59+
2. 初始时,将所有香槟倒入顶层杯子:$dp[0][0] = poured$。
60+
3. 对于每个杯子 $dp[i][j]$:
61+
- 如果 $dp[i][j] > 1$,说明有香槟溢出。
62+
- 溢出的香槟量为 $overflow = (dp[i][j] - 1) / 2$。
63+
- 将溢出的香槟平均分配给下一层的两个杯子:$dp[i+1][j]$ 和 $dp[i+1][j+1]$。
64+
4. 最后返回 $\min(1, dp[query\_row][query\_glass])$,因为杯子最多只能装 $1$ 杯香槟。
65+
66+
**优化**:由于只需要计算到第 $query\_row$ 行,所以只需要模拟到该行即可。
67+
68+
### 思路 1:代码
69+
70+
```python
71+
class Solution:
72+
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
73+
# dp[i][j] 表示第 i 行第 j 个杯子中的香槟量
74+
dp = [[0.0] * (query_row + 2) for _ in range(query_row + 2)]
75+
dp[0][0] = poured
76+
77+
# 模拟香槟倾倒过程
78+
for i in range(query_row + 1):
79+
for j in range(i + 1):
80+
if dp[i][j] > 1:
81+
# 计算溢出的香槟量
82+
overflow = (dp[i][j] - 1) / 2.0
83+
# 将溢出的香槟平均分配给下一层的两个杯子
84+
dp[i + 1][j] += overflow
85+
dp[i + 1][j + 1] += overflow
86+
87+
# 返回目标杯子中的香槟量,最多为 1
88+
return min(1.0, dp[query_row][query_glass])
89+
```
90+
91+
### 思路 1:复杂度分析
92+
93+
- **时间复杂度**:$O(query\_row^2)$。需要遍历前 $query\_row + 1$ 行的所有杯子。
94+
- **空间复杂度**:$O(query\_row^2)$。需要存储前 $query\_row + 1$ 行的所有杯子的状态。

0 commit comments

Comments
 (0)