文章目录
- 第一章,简单介绍
-
- [**1️⃣ 什么是算法?**](#1️⃣ 什么是算法?)
- [**2️⃣ 数据结构与算法的关系**](#2️⃣ 数据结构与算法的关系)
- [**3️⃣ Python 示例**](#3️⃣ Python 示例)
- [**4️⃣ 学习建议**](#4️⃣ 学习建议)
- 递归、迭代以及复杂度分析
-
- [1️⃣ 递归与迭代的概念](#1️⃣ 递归与迭代的概念)
- [2️⃣ 时间复杂度与空间复杂度](#2️⃣ 时间复杂度与空间复杂度)
- [3️⃣ Python 示例](#3️⃣ Python 示例)
-
- [(A) 递归阶乘](#(A) 递归阶乘)
- [(B) 迭代阶乘](#(B) 迭代阶乘)
- [4️⃣ 初学者理解小技巧](#4️⃣ 初学者理解小技巧)
- [5️⃣ 总结](#5️⃣ 总结)
- 练习题以及答案
-
- [**Day 1:算法与数据结构练习**](#Day 1:算法与数据结构练习)
-
- [练习题 1️⃣:插入排序(扑克整理)](#练习题 1️⃣:插入排序(扑克整理))
- [练习题 2️⃣:贪婪找零](#练习题 2️⃣:贪婪找零)
- [**Day 2:递归与迭代练习**](#Day 2:递归与迭代练习)
-
- [练习题 3️⃣:递归阶乘](#练习题 3️⃣:递归阶乘)
- [练习题 4️⃣:迭代阶乘](#练习题 4️⃣:迭代阶乘)
第一章,简单介绍
1️⃣ 什么是算法?
算法就是一套明确的步骤,用来解决问题,特点:
- 输入输出明确:明确知道算法处理什么输入,输出什么结果。
- 步骤可行且有限:每一步操作可以执行,并且算法总会在有限步骤内完成。
- 相同输入总是得到相同输出:保证结果可预测。
生活中的例子
-
查字典(二分搜索算法)
- 想查拼音首字母为 R 的字
- 翻到中间,判断字母是前还是后
- 逐步缩小查找范围,直到找到
→ 数据结构是已排序的数组,算法是二分搜索。
-
整理扑克牌(插入排序算法)
- 把手牌分为有序和无序部分
- 每次从无序部分抽一张牌,插入到有序部分正确位置
- 重复,直到牌全部有序
-
找零问题(贪婪算法)
- 买东西找钱,每次选当前能用的最大面额,直到凑够总额
- 每一步都选"当前最优方案"
2️⃣ 数据结构与算法的关系
- 数据结构:组织和存储数据的方法(数组、链表、树、哈希表等)
- 算法:操作这些数据结构的步骤
关系:
- 数据结构是算法的基础
- 算法为数据结构赋能
- 选择合适的数据结构能显著提高效率
类比积木:
- 积木块 → 数据
- 积木的形状和连接方式 → 数据结构
- 拼装步骤 → 算法
- 最终积木模型 → 输出结果
3️⃣ Python 示例
插入排序(整理扑克牌)
python
def insertion_sort(arr):
"""
插入排序算法:将列表从小到大排序
思路:
1. 从第二个元素开始,取当前元素 key
2. 将 key 插入到左边已排序部分的正确位置
3. 重复直到整个列表有序
"""
for i in range(1, len(arr)):
key = arr[i] # 当前要插入的元素
j = i - 1
# 向左扫描已排序部分,如果大于 key,则右移
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j] # 数据右移
j -= 1
arr[j + 1] = key # 插入 key
return arr
# 测试
cards = [5, 3, 6, 2, 4]
print(insertion_sort(cards)) # 输出:[2, 3, 4, 5, 6]
贪婪找零算法
python
def greedy_change(amount, coins):
"""
贪婪找零算法
参数:
- amount: 需要找的总金额
- coins: 可用的硬币面额列表
返回:
- 一个列表,表示找零方案
思路:
1. 将硬币从大到小排序
2. 每次使用当前最大面额的硬币,直到凑够总额
"""
coins.sort(reverse=True) # 从大到小排序
result = []
for coin in coins:
while amount >= coin:
amount -= coin
result.append(coin)
return result
# 测试
coins = [20, 10, 5, 1]
amount = 31
print(greedy_change(amount, coins)) # 输出:[20, 10, 1]
4️⃣ 学习建议
- 理解概念:先理解算法逻辑,再看代码实现。
- 动手实践:敲代码、调试输出,观察算法如何改变数据。
- 联系生活:把查字典、整理扑克牌、找零问题想成生活小任务。
递归、迭代以及复杂度分析
1️⃣ 递归与迭代的概念
迭代(Iteration)
迭代是通过重复执行一段代码来完成任务,通常用 for 或 while 循环实现。每一步都是显式的"循环操作",非常直观。
递归(Recursion)
递归是函数自己调用自己来完成任务。递归通常有两个部分:
- 终止条件(Base case):当问题规模最小或满足条件时,不再递归。
- 递归步骤(Recursive step):将问题拆解为更小的子问题,并通过函数自身求解。
💡 核心区别:迭代用循环显式推进,递归通过函数调用隐式推进。
2️⃣ 时间复杂度与空间复杂度
-
时间复杂度:算法执行所需时间的增长量。比如阶乘函数对 n 的计算量:
- 迭代:O(n)
- 递归:O(n)
-
空间复杂度:算法执行所需额外空间:
- 迭代:O(1)(常量空间)
- 递归:O(n)(递归调用会占用栈空间)
所以递归虽然逻辑简洁,但可能占用更多内存,需要注意"栈溢出"问题。
3️⃣ Python 示例
(A) 递归阶乘
python
def factorial_recursive(n):
"""
递归实现阶乘
阶乘 n! = n * (n-1)!, 0! = 1
"""
if n == 0 or n == 1: # 终止条件
return 1
return n * factorial_recursive(n - 1) # 递归调用
# 测试
print(factorial_recursive(5)) # 输出: 120
(B) 迭代阶乘
python
def factorial_iterative(n):
"""
迭代实现阶乘
通过循环累乘
"""
result = 1
for i in range(2, n + 1):
result *= i # 累乘
return result
# 测试
print(factorial_iterative(5)) # 输出: 120
4️⃣ 初学者理解小技巧
-
手动演算:
-
对
factorial_recursive(4),手动画出函数调用栈:factorial_recursive(4) -> 4 * factorial_recursive(3) -> 3 * factorial_recursive(2) -> 2 * factorial_recursive(1) -> 1然后从栈底向上计算:1 → 2 → 6 → 24
-
-
对比迭代:
- 用循环累乘:2 → 6 → 24,过程更直观,但没有"函数栈"的概念。
-
复杂度分析:
- 两者时间复杂度相同 O(n)
- 递归额外消耗栈空间 O(n),迭代只需要一个变量 O(1)
5️⃣ 总结
- 递归适合逻辑清晰、可分解为相似子问题的场景(如树遍历、分治问题)。
- 迭代适合对空间敏感或者操作简单的线性任务。
- 复杂度分析帮助你理解算法在大规模输入下的性能表现,是算法设计的基础。
练习题以及答案
Day 1:算法与数据结构练习
练习题 1️⃣:插入排序(扑克整理)
题目 :给定列表 [7, 2, 5, 3, 4],用插入排序将它从小到大排序,并画出每一步元素移动的变化过程。
参考代码:
python
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j] # 元素右移
j -= 1
arr[j + 1] = key
return arr
cards = [7, 2, 5, 3, 4]
print(insertion_sort(cards)) # 输出: [2, 3, 4, 5, 7]
讲解:
- 从第二个元素
2开始,向左扫描[7],发现7>2,右移7,插入2→[2,7,5,3,4] - 取
5,扫描[2,7],右移7,插入5→[2,5,7,3,4] - 取
3,扫描[2,5,7],右移7,5,插入3→[2,3,5,7,4] - 取
4,扫描[2,3,5,7],右移7,5,插入4→[2,3,4,5,7]
每一步都是把"未排序的元素"插入到"已排序部分"的正确位置。
练习题 2️⃣:贪婪找零
题目 :超市买东西找零,硬币面额 [10,5,2,1],总金额 18,每次选择最大可用面额的硬币,计算找零方案。
参考代码:
python
def greedy_change(amount, coins):
coins.sort(reverse=True)
result = []
for coin in coins:
while amount >= coin:
amount -= coin
result.append(coin)
return result
coins = [10, 5, 2, 1]
amount = 18
print(greedy_change(amount, coins)) # 输出: [10,5,2,1]
讲解:
-
贪婪策略:每一步都选择当前能用的最大面额。
-
步骤:
- 用
10→ 剩余8 - 用
5→ 剩余3 - 用
2→ 剩余1 - 用
1→ 剩余0
- 用
-
优点:逻辑简单,效率高。缺点:在某些面额组合下可能不是最优(此例最优)。
Day 2:递归与迭代练习
练习题 3️⃣:递归阶乘
题目 :实现函数 factorial_recursive(n),用递归计算阶乘 n!,测试 n=5。
参考代码:
python
def factorial_recursive(n):
if n == 0 or n == 1: # 终止条件
return 1
return n * factorial_recursive(n - 1)
print(factorial_recursive(5)) # 输出: 120
讲解:
-
核心思路:
n! = n * (n-1)! -
调用栈展开过程:
factorial_recursive(5) -> 5 * factorial_recursive(4) -> 4 * factorial_recursive(3) -> 3 * factorial_recursive(2) -> 2 * factorial_recursive(1) -> 1 -
从栈底开始返回计算结果:1 → 2 → 6 → 24 → 120
练习题 4️⃣:迭代阶乘
题目 :实现函数 factorial_iterative(n),用循环计算阶乘,测试 n=5。
参考代码:
python
def factorial_iterative(n):
result = 1
for i in range(2, n+1):
result *= i
return result
print(factorial_iterative(5)) # 输出: 120
讲解:
- 通过循环依次累乘
2*3*4*5,直观且节省递归栈空间。 - 时间复杂度与递归相同 O(n),但空间复杂度更低 O(1)。
💡 学习提示:
- 对插入排序和贪婪找零,可以画出每一步元素移动或找零选择过程,更直观理解算法逻辑。
- 对递归阶乘,建议手动画调用栈,理解"从终止条件返回结果"的顺序。
- 可尝试对比迭代与递归,观察时间和空间消耗差异,加深复杂度分析理解。