Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8630e96

Browse files
committed
修复和优化语句表述
1 parent d5e9252 commit 8630e96

File tree

1 file changed

+67
-143
lines changed

1 file changed

+67
-143
lines changed

‎docs/07_algorithm/07_01_enumeration_algorithm.md‎

Lines changed: 67 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,79 @@
11
## 1. 枚举算法简介
22

3-
> **枚举算法(Enumeration Algorithm)**:也称为穷举算法,指的是按照问题本身的性质,一一列举出该问题所有可能的解,并在逐一列举的过程中,将它们逐一与目标状态进行比较以得出满足问题要求的解。在列举的过程中,既不能遗漏也不能重复
3+
> **枚举算法(Enumeration Algorithm)**,又称穷举算法,是指根据问题的特点,逐一列出所有可能的解,并与目标条件进行比较,找出满足要求的答案。枚举时要确保不遗漏、不重复
44
5-
枚举算法的核心思想是:通过列举问题的所有状态,将它们逐一与目标状态进行比较,从而得到满足条件的解
5+
枚举算法的核心思想就是:遍历所有可能的状态,逐个判断是否满足条件,找到符合要求的解
66

7-
由于枚举算法要通过列举问题的所有状态来得到满足条件的解,因此,在问题规模变大时,其效率一般是比较低的。但是枚举算法也有自己特有的优点:
7+
由于需要遍历所有状态,枚举算法在问题规模较大时效率较低。但它也有明显优点:
88

9-
1. 多数情况下容易编程实现,也容易调试
10-
2. 建立在考察大量状态、甚至是穷举所有状态的基础上,所以算法的正确性比较容易证明
9+
1. 实现简单,易于编程和调试
10+
2. 基于穷举所有情况,正确性容易验证
1111

12-
所以,枚举算法通常用于求解问题规模比较小的问题,或者作为求解问题的一个子算法出现,通过枚举一些信息并进行保存,而这些消息的有无对主算法效率的高低有着较大影响
12+
因此,枚举算法常用于小规模问题,或作为其他算法的辅助工具,通过枚举部分信息来提升主算法的效率
1313

1414
## 2. 枚举算法的解题思路
1515

1616
### 2.1 枚举算法的解题思路
1717

18-
枚举算法是设计最简单、最基本的搜索算法。是我们在遇到问题时,最应该优先考虑的算法
18+
枚举算法是最简单、最基础的搜索方法,通常是遇到问题时的首选方案
1919

20-
因为其实现足够简单,所以在遇到问题时,我们往往可以先通过枚举算法尝试解决问题,然后在此基础上,再去考虑其他优化方法和解题思路
20+
由于实现简单,我们可以先用枚举算法尝试解决问题,再考虑是否需要优化
2121

22-
采用枚举算法解题的一般思路如下:
22+
枚举算法的基本步骤如下:
2323

24-
1. 确定枚举对象、枚举范围和判断条件,并判断条件设立的正确性
25-
2. 一一枚举可能的情况,并验证是否是问题的解
26-
3. 考虑提高枚举算法的效率
24+
1. 明确需要枚举的对象、枚举范围和约束条件
25+
2. 逐一枚举所有可能情况,判断是否满足题意
26+
3. 思考如何提升枚举效率
2727

28-
我们可以从下面几个方面考虑提高算法的效率:
28+
提升效率的常用方法有:
2929

30-
1. 抓住问题状态的本质,尽可能缩小问题状态空间的大小
31-
2. 加强约束条件,缩小枚举范围
32-
3. 根据某些问题特有的性质,例如对称性等,避免对本质相同的状态重复求解
30+
- 抓住问题本质,尽量缩小状态空间
31+
- 增加约束条件,减少无效枚举
32+
- 利用某些问题特有的性质(例如对称性等),避免重复计算
3333

3434
### 2.2 枚举算法的简单应用
3535

36-
下面举个著名的例子:「百钱买百鸡问题」。这个问题是我国古代数学家张丘在「算经」一书中提出的。该问题叙述如下:
36+
以经典的「百钱买百鸡问题」为例:
3737

38-
> **百钱买百鸡问题**:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则鸡翁、鸡母、鸡雏各几何?
38+
> **问题**:公鸡 5 元/只,母鸡 3 元/只,小鸡 1 元/3 只。用 100 元买 100 只鸡,问各买多少只?
3939
40-
翻译一下,意思就是:公鸡一只五块钱,母鸡一只三块钱,小鸡三只一块钱。现在我们用 100ドル$ 块钱买了 100ドル$ 只鸡,问公鸡、母鸡、小鸡各买了多少只?
40+
**解题步骤**:
4141

42-
下面我们根据算法的一般思路来解决一下这道题。
42+
1. **确定枚举对象和范围**
43+
- 枚举对象:公鸡数 $x,ドル母鸡数 $y,ドル小鸡数 $z$
44+
- 枚举范围:0ドル \le x, y, z \le 100$
45+
- 约束条件:5ドルx + 3y + \frac{z}{3} = 100$ 且 $x + y + z = 100$
4346

44-
1. 确定枚举对象、枚举范围和判断条件,并判断条件设立的正确性。
47+
2.**暴力枚举**
4548

46-
1. 确定枚举对象:枚举对象为公鸡、母鸡、小鸡的只数,那么我们可以用变量 $x$、$y$、$z$ 分别来代表公鸡、母鸡、小鸡的只数。
47-
2. 确定枚举范围:因为总共买了 100ドル$ 只鸡,所以 0ドル \le x, y, z \le 100,ドル则 $x$、$y$、$z$ 的枚举范围为 $[0, 100]$。
48-
3. 确定判断条件:根据题意,我们可以列出两个方程式:5ドル \times x + 3 \times y + \frac{z}{3} = 100,ドル$x + y + z = 100$。在枚举 $x$、$y$、$z$ 的过程中,我们可以根据这两个方程式来判断是否当前状态是否满足题意。
49+
```python
50+
class Solution:
51+
def buyChicken(self):
52+
for x in range(101):
53+
for y in range(101):
54+
for z in range(101):
55+
if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100 and x + y + z == 100:
56+
print("公鸡 %s 只,母鸡 %s 只,小鸡 %s" % (x, y, z))
57+
```
4958

50-
2. 一一枚举可能的情况,并验证是否是问题的解。
59+
3. **优化枚举效率**
60+
- 利用 $z = 100 - x - y$ 减少一重循环
61+
- 缩小枚举范围:$x \in [0, 20],ドル$y \in [0, 33]$
5162

52-
1. 根据枚举对象、枚举范围和判断条件,我们可以顺利写出对应的代码。
53-
54-
```python
55-
class Solution:
56-
def buyChicken(self):
57-
for x in range(101):
58-
for y in range(101):
59-
for z in range(101):
60-
if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100 and x + y + z == 100:
61-
print("公鸡 %s 只,母鸡 %s 只,小鸡 %s" % (x, y, z))
62-
```
63-
64-
3. 考虑提高枚举算法的效率。
65-
66-
1. 在上面的代码中,我们枚举了 $x$$y$$z$,但其实根据方程式 $x + y + z = 100$,得知:$z$ 可以通过 $z = 100 - x - y$ 而得到,这样我们就不用再枚举 $z$ 了。
67-
2. 在上面的代码中,对 $x$$y$ 的枚举范围是 $[0, 100]$,但其实如果所有钱用来买公鸡,最多只能买 $20$ 只,同理,全用来买母鸡,最多只能买 $33$ 只。所以对 $x$ 的枚举范围可改为 $[0, 20]$,$y$ 的枚举范围可改为 $[0, 33]$
68-
69-
```python
70-
class Solution:
71-
def buyChicken(self):
72-
for x in range(21):
73-
for y in range(34):
74-
z = 100 - x - y
75-
if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100:
76-
print("公鸡 %s 只,母鸡 %s 只,小鸡 %s" % (x, y, z))
77-
```
63+
```python
64+
class Solution:
65+
def buyChicken(self):
66+
for x in range(21):
67+
for y in range(34):
68+
z = 100 - x - y
69+
if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100:
70+
print("公鸡 %s 只,母鸡 %s 只,小鸡 %s" % (x, y, z))
71+
```
7872

7973

8074
## 3. 枚举算法的应用
8175

82-
### 3.1 两数之和
76+
### 3.1 经典例题:两数之和
8377

8478
#### 3.1.1 题目链接
8579

@@ -117,109 +111,38 @@
117111

118112
#### 3.1.3 解题思路
119113

120-
这里说下枚举算法的解题思路。
121-
122114
##### 思路 1:枚举算法
123115

124-
1. 使用两重循环枚举数组中每一个数 $nums[i]$、$nums[j],ドル判断所有的 $nums[i] + nums[j]$ 是否等于 $target$。
125-
2. 如果出现 $nums[i] + nums[j] == target,ドル则说明数组中存在和为 $target$ 的两个整数,将两个整数的下标 $i$、$j$ 输出即可
116+
1. 通过两重循环,依次枚举数组中所有可能的下标对 $(i, j)$(其中 $i < j$),判断 $nums[i] + nums[j]$ 是否等于 $target$。
117+
2. 一旦找到满足条件的下标对,即 $nums[i] + nums[j] == target,ドル立即返回这两个下标 $[i, j]$ 作为答案
126118

127119
##### 思路 1:代码
128120

129121
```python
130122
class Solution:
131123
def twoSum(self, nums: List[int], target: int) -> List[int]:
124+
# 遍历第一个数的下标
132125
for i in range(len(nums)):
126+
# 遍历第二个数的下标(只需从i+1开始,避免和自身重复)
133127
for j in range(i + 1, len(nums)):
134-
if i != j and nums[i] + nums[j] == target:
135-
return [i, j]
136-
return []
128+
# 判断两数之和是否等于目标值
129+
if nums[i] + nums[j] == target:
130+
return [i, j] # 返回下标对
131+
return [] # 如果没有找到,返回空列表
137132
```
138133

139134
##### 思路 1:复杂度分析
140135

141136
- **时间复杂度**:$O(n^2),ドル其中 $n$ 为数组 $nums$ 的元素数量。
142137
- **空间复杂度**:$O(1)$。
143138

144-
### 3.2 计数质数
139+
### 3.2 统计平方和三元组的数目
145140

146141
#### 3.2.1 题目链接
147142

148-
- [204. 计数质数 - 力扣(LeetCode)](https://leetcode.cn/problems/count-primes/)
149-
150-
#### 3.2.2 题目大意
151-
152-
**描述**:给定 一个非负整数 $n$。
153-
154-
**要求**:统计小于 $n$ 的质数数量。
155-
156-
**说明**:
157-
158-
- 0ドル \le n \le 5 \times 10^6$。
159-
160-
**示例**:
161-
162-
- 示例 1:
163-
164-
```python
165-
输入 n = 10
166-
输出 4
167-
解释 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7
168-
```
169-
170-
- 示例 2:
171-
172-
```python
173-
输入:n = 1
174-
输出:0
175-
```
176-
177-
#### 3.2.3 解题思路
178-
179-
这里说下枚举算法的解题思路(注意:提交会超时,只是讲解一下枚举算法的思路)。
180-
181-
##### 思路 1:枚举算法(超时)
182-
183-
对于小于 $n$ 的每一个数 $x,ドル我们可以枚举区间 $[2, x - 1]$ 上的数是否是 $x$ 的因数,即是否存在能被 $x$ 整除的数。如果存在,则该数 $x$ 不是质数。如果不存在,则该数 $x$ 是质数。
184-
185-
这样我们就可以通过枚举 $[2, n - 1]$ 上的所有数 $x,ドル并判断 $x$ 是否为质数。
186-
187-
在遍历枚举的同时,我们维护一个用于统计小于 $n$ 的质数数量的变量 $cnt$。如果符合要求,则将计数 $cnt$ 加 1ドル$。最终返回该数目作为答案。
188-
189-
考虑到如果 $i$ 是 $x$ 的因数,则 $\frac{x}{i}$ 也必然是 $x$ 的因数,则我们只需要检验这两个因数中的较小数即可。而较小数一定会落在 $[2, \sqrt x]$ 上。因此我们在检验 $x$ 是否为质数时,只需要枚举 $[2, \sqrt x]$ 中的所有数即可。
190-
191-
利用枚举算法单次检查单个数的时间复杂度为 $O(\sqrt{n}),ドル检查 $n$ 个数的整体时间复杂度为 $O(n \sqrt{n})$。
192-
193-
##### 思路 1:代码
194-
195-
```python
196-
class Solution:
197-
def isPrime(self, x):
198-
for i in range(2, int(pow(x, 0.5)) + 1):
199-
if x % i == 0:
200-
return False
201-
return True
202-
203-
def countPrimes(self, n: int) -> int:
204-
cnt = 0
205-
for x in range(2, n):
206-
if self.isPrime(x):
207-
cnt += 1
208-
return cnt
209-
```
210-
211-
##### 思路 1:复杂度分析
212-
213-
- **时间复杂度**:$O(n \times \sqrt{n})$。
214-
- **空间复杂度**:$O(1)$。
215-
216-
### 3.3 统计平方和三元组的数目
217-
218-
#### 3.3.1 题目链接
219-
220143
- [1925. 统计平方和三元组的数目 - 力扣(LeetCode)](https://leetcode.cn/problems/count-square-sum-triples/)
221144

222-
#### 3.3.2 题目大意
145+
#### 3.2.2 题目大意
223146

224147
**描述**:给你一个整数 $n$。
225148

@@ -248,30 +171,31 @@ class Solution:
248171
解释:平方和三元组为 (3,4,5),(4,3,5),(6,8,10) 和 (8,6,10)。
249172
```
250173

251-
#### 3.3.3 解题思路
174+
#### 3.2.3 解题思路
252175

253176
##### 思路 1:枚举算法
254177

255-
我们可以在 $[1, n]$ 区间中枚举整数三元组 $(a, b, c)$ 中的 $a$ 和 $b$。然后判断 $a^2 + b^2$ 是否小于等于 $n,ドル并且是完全平方数
178+
直接枚举 $a$ 和 $b$,计算 $c^2 = a^2 + b^2$,判断 $c$ 是否为整数且 1ドル \leq c \leq n,ドル如果满足条件则计数加一,最后返回总数
256179

257-
在遍历枚举的同时,我们维护一个用于统计平方和三元组数目的变量 $cnt$。如果符合要求,则将计数 $cnt$ 加 1ドル$。最终,我们返回该数目作为答案
180+
该方法时间复杂度为 $O(n^2)$
258181

259-
利用枚举算法统计平方和三元组数目的时间复杂度为 $O(n^2)$。
260182

261-
- 注意:在计算中,为了防止浮点数造成的误差,并且两个相邻的完全平方正数之间的距离一定大于 1ドル,ドル所以我们可以用 $\sqrt{a^2 + b^2 + 1}$ 来代替 $\sqrt{a^2 + b^2}$。
183+
- 注意:为避免浮点误差,可以用 $\sqrt{a^2 + b^2 + 1}$ 代替 $\sqrt{a^2 + b^2}$,这样判断 $c$ 是否为整数更安全
262184

263185
##### 思路 1:代码
264186

265187
```python
266188
class Solution:
267189
def countTriples(self, n: int) -> int:
268-
cnt = 0
269-
for a in range(1, n + 1):
270-
for b in range(1, n + 1):
190+
cnt = 0 # 统计满足条件的三元组个数
191+
for a in range(1, n + 1): # 枚举 a
192+
for b in range(1, n + 1): # 枚举 b
193+
# 计算 c,注意加 1 防止浮点误差
271194
c = int(sqrt(a * a + b * b + 1))
195+
# 判断 c 是否在范围内,且 a^2 + b^2 == c^2
272196
if c <= n and a * a + b * b == c * c:
273-
cnt += 1
274-
return cnt
197+
cnt += 1# 满足条件,计数加一
198+
return cnt# 返回最终统计结果
275199
```
276200

277201
##### 思路 1:复杂度分析

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /