1. 算法是什么一个生活化的理解1.1 从做西红柿炒蛋说起想象你要教一个完全不会做饭的人做西红柿炒蛋你会怎么写步骤步骤1准备2个西红柿洗净切块 步骤2打3个鸡蛋加盐搅拌均匀 步骤3热锅倒油油热后倒入蛋液 步骤4蛋液凝固后盛出备用 步骤5锅中再倒少许油放入西红柿翻炒 步骤6西红柿出汁后倒入炒好的鸡蛋 步骤7加盐调味翻炒均匀后出锅这就是算法一系列明确的、有限的、可执行的步骤用于解决特定问题做出一道菜。1.2 算法的正式定义算法Algorithm解决特定问题的一系列清晰指令满足以下特性有穷性必须在有限步骤内结束确定性每条指令含义明确无歧义可行性每条指令都可以通过基本操作实现输入零个或多个输入输出至少一个输出# 算法 vs 程序# 算法是思想程序是实现# 算法找出列表中的最大值# 思路假设第一个最大逐个比较更新# 程序Python 实现deffind_max(arr):ifnotarr:returnNonemax_valarr[0]# 假设第一个最大fornuminarr[1:]:# 逐个比较ifnummax_val:max_valnum# 更新最大值returnmax_val# 测试numbers[3,1,4,1,5,9,2,6]print(f最大值是{find_max(numbers)})# 91.3 算法无处不在场景算法在做什么刷短视频推荐算法判断你喜欢什么地图导航最短路径算法规划路线扫码支付加密算法保护交易安全搜索引擎排序算法索引算法找到最相关结果人脸识别深度学习算法提取特征快递分拣调度算法优化配送路径核心认知算法不是程序员的专属它是解决问题的通用方法论。学算法就是学如何高效思考。2. 算法与程序灵魂与躯壳2.1 同一个算法多种实现问题计算 1 2 3 … 100算法一逐个累加循环defsum_naive(n):逐个相加total0foriinrange(1,n1):totalireturntotalprint(sum_naive(100))# 5050算法二高斯求和公式数学defsum_gauss(n):高斯算法n * (n 1) / 2returnn*(n1)//2print(sum_gauss(100))# 5050算法三递归defsum_recursive(n):递归sum(n) n sum(n-1)ifn1:return1returnnsum_recursive(n-1)print(sum_recursive(100))# 5050对比实现时间复杂度空间复杂度特点逐个累加O(n)O(1)直观但慢高斯公式O(1)O(1)最优瞬间完成递归O(n)O(n)优雅但有栈开销启示算法决定效率的上限程序决定实现的质量。高斯公式这个算法本身就比逐个累加快无数倍——这是算法层面的碾压。2.2 算法的层次┌─────────────────────────────────────────┐ │ 第4层数学算法最优 │ │ 如高斯求和、矩阵快速幂 │ ├─────────────────────────────────────────┤ │ 第3层高级数据结构算法 │ │ 如平衡树、图算法、动态规划 │ ├─────────────────────────────────────────┤ │ 第2层基础算法 │ │ 如排序、搜索、递归、分治 │ ├─────────────────────────────────────────┤ │ 第1层暴力枚举 │ │ 如逐个尝试所有可能 │ └─────────────────────────────────────────┘3. 为什么算法如此重要3.1 场景一从能用到好用假设你在开发一个用户搜索功能方案A暴力搜索defsearch_users(users,keyword):在用户列表中搜索暴力匹配results[]foruserinusers:ifkeywordinuser[name]orkeywordinuser[email]:results.append(user)returnresults# 1000个用户0.1秒 ✓# 100万个用户100秒 ✗ 用户已经关闭页面了方案B使用索引算法优化fromcollectionsimportdefaultdictclassUserSearchEngine:def__init__(self):self.indexdefaultdict(set)# 倒排索引defadd_user(self,user):建立索引wordsuser[name].lower().split()wordsuser[email].lower().split()forwordinwords:self.index[word].add(user[id])defsearch(self,keyword):基于索引搜索keywordkeyword.lower()returnself.index.get(keyword,set())# 100万个用户0.001秒 ✓✓✓# 性能提升 10万倍这就是算法的威力同样的功能不同的算法用户体验天差地别。3.2 场景二资源有限时的生存法则真实案例NASA 的火星探测器约束条件 - 处理器200MHz比你的手机慢50倍 - 内存256MB - 通信延迟4~24分钟地球到火星 - 电量太阳能有限 没有优秀算法 任务失败3.3 场景三面试与职业发展的硬通货国内大厂面试算法题占比 ┌─────────────────┬─────────────┐ │ 公司 │ 算法题占比 │ ├─────────────────┼─────────────┤ │ 字节跳动 │ 70% │ │ 阿里巴巴 │ 60% │ │ 腾讯 │ 55% │ │ 美团 │ 65% │ │ Google │ 75% │ │ Meta │ 70% │ └─────────────────┴─────────────┘ 为什么因为算法能力是可迁移的智力。3.4 算法重要性的四个维度效率 ↑ 快 ←──┼──→ 省 (时间) │ (空间) ↓ 正确 第5维度可维护性代码可读、可扩展4. 如何衡量算法的好坏4.1 不是跑得快这么简单importtimedeftest_performance():同一算法在不同数据下的表现# 算法冒泡排序defbubble_sort(arr):nlen(arr)foriinrange(n):forjinrange(0,n-i-1):ifarr[j]arr[j1]:arr[j],arr[j1]arr[j1],arr[j]returnarr# 测试不同规模forsizein[100,1000,5000]:arrlist(range(size,0,-1))# 最坏情况逆序starttime.time()bubble_sort(arr.copy())elapsedtime.time()-startprint(f规模{size:5d}:{elapsed:.4f}秒)test_performance()典型输出规模 100: 0.0012秒 规模 1000: 0.0891秒 规模 5000: 2.3124秒 ← 规模×5时间×26⚠️问题运行时间受硬件、语言、当前系统负载影响不能作为衡量标准。4.2 正确的衡量方式复杂度分析我们需要一种与机器无关的衡量方式关注算法本身的效率随数据规模增长的变化趋势。5. 算法复杂度Big O 表示法5.1 什么是 Big OBig O 表示法描述算法运行时间或空间随输入规模增长的变化趋势。核心思想当 n → ∞ 时只保留增长最快的项忽略常数和低阶项。精确计算T(n) 3n² 5n 100 Big O O(n²) ← 只保留最高阶 为什么可以忽略 当 n 100万时 3n² 3,000,000,000,000 5n 5,000,000 100 100 5n 100 相对于 3n² 可以忽略不计5.2 常见复杂度对比复杂度名称示例n10n100n1000O(1)常数数组随机访问111O(log n)对数二分查找3710O(n)线性遍历数组101001000O(n log n)线性对数快速排序3070010,000O(n²)平方冒泡排序10010,0001,000,000O(n³)立方三重循环10001,000,00010⁹O(2ⁿ)指数子集枚举1024≈10³⁰≈10³⁰¹O(n!)阶乘全排列3,628,800≈10¹⁵⁸宇宙原子数≪可视化增长曲线操作次数 ↑ │ 1e30 ┤ ★ 2ⁿ │ ★ 1e20 ┤ ★ │ ★ 1e9 ┤ ★ │ ★ ▲ n³ 1e6 ┤ ★ ▲ │★ ▲ 1e3 ┤ ▲ │▲ 10 ┼────┬────┬────┬────┬────→ n 0 10 50 100 500 1000 ★ 指数 ▲ 立方 ● 平方 ■ nlogn ◆ 线性 ◇ 对数5.3 复杂度分析实战示例1单层循环defexample1(arr):时间复杂度O(n)total0fornuminarr:# 执行 n 次totalnumreturntotal示例2双层循环defexample2(arr):时间复杂度O(n²)count0foriinarr:# 执行 n 次forjinarr:# 每次执行 n 次ifij0:count1returncount# 总操作n × n n²示例3循环折半defexample3(n):时间复杂度O(log n)count0whilen0:# n 每次减半nn//2count1returncount# n16: 16→8→4→2→1执行4次 log₂16# n1024: 执行10次 log₂1024示例4递归defexample4(n):时间复杂度O(2ⁿ)ifn1:return1returnexample4(n-1)example4(n-1)# 调用树# f(4)# / \# f(3) f(3)# / \ / \# f(2) f(2) f(2) f(2)# ... 共 2⁴ - 1 15 个节点5.4 空间复杂度defsum_iterative(n):空间复杂度O(1)total0foriinrange(1,n1):totalireturntotaldefsum_recursive(n):空间复杂度O(n) - 调用栈深度ifn1:return1returnnsum_recursive(n-1)defcreate_matrix(n):空间复杂度O(n²)return[[0]*nfor_inrange(n)]6. Python 实现经典算法6.1 搜索算法线性搜索O(n)deflinear_search(arr,target):逐个查找最坏遍历全部fori,numinenumerate(arr):ifnumtarget:returni# 找到返回索引return-1# 未找到# 适用无序数据数据量小二分搜索O(log n)defbinary_search(arr,target): 二分搜索每次排除一半数据 前提数组必须有序 left,right0,len(arr)-1whileleftright:mid(leftright)//2ifarr[mid]target:returnmid# 找到elifarr[mid]target:leftmid1# 目标在右半区else:rightmid-1# 目标在左半区return-1# 未找到# 测试sorted_arr[1,3,5,7,9,11,13,15,17,19]print(binary_search(sorted_arr,7))# 3print(binary_search(sorted_arr,10))# -1# 性能对比# 线性搜索 100万个元素最坏100万次比较# 二分搜索 100万个元素最多20次比较6.2 排序算法选择排序O(n²)defselection_sort(arr): 思路每次从未排序区选最小放到已排序区末尾 nlen(arr)foriinrange(n):min_idxiforjinrange(i1,n):ifarr[j]arr[min_idx]:min_idxj arr[i],arr[min_idx]arr[min_idx],arr[i]returnarr# 直观但低效仅用于教学快速排序O(n log n) 平均defquick_sort(arr): 分治策略 1. 选基准pivot 2. 分区小于放左大于放右 3. 递归排序左右子数组 iflen(arr)1:returnarr pivotarr[len(arr)//2]# 选中间元素为基准left[xforxinarrifxpivot]middle[xforxinarrifxpivot]right[xforxinarrifxpivot]returnquick_sort(left)middlequick_sort(right)# 测试arr[64,34,25,12,22,11,90]print(quick_sort(arr))# [11, 12, 22, 25, 34, 64, 90]归并排序稳定 O(n log n)defmerge_sort(arr):分治先分后合iflen(arr)1:returnarr midlen(arr)//2leftmerge_sort(arr[:mid])rightmerge_sort(arr[mid:])returnmerge(left,right)defmerge(left,right):合并两个有序数组result[]ij0whileilen(left)andjlen(right):ifleft[i]right[j]:result.append(left[i])i1else:result.append(right[j])j1result.extend(left[i:])result.extend(right[j:])returnresult6.3 排序算法性能对比importrandomimporttimedefcompare_sorts():对比不同排序算法的实际性能algorithms{选择排序:selection_sort,快速排序:quick_sort,归并排序:merge_sort,Python内置:sorted,}sizes[100,1000,5000]print(f{规模:8},end)fornameinalgorithms:print(f{name:12},end)print()print(-*60)forsizeinsizes:arr[random.randint(1,10000)for_inrange(size)]print(f{size:8},end)forname,funcinalgorithms.items():test_arrarr.copy()starttime.time()func(test_arr)elapsedtime.time()-startprint(f{elapsed:11.4f}s,end)print()compare_sorts()典型输出规模 选择排序 快速排序 归并排序 Python内置 ------------------------------------------------------------ 100 0.0012s 0.0003s 0.0004s 0.0000s 1000 0.0891s 0.0021s 0.0032s 0.0001s 5000 2.3124s 0.0123s 0.0187s 0.0008s为什么内置 sorted 最快Python 的sorted()使用Timsort是归并排序插入排序的混合算法针对真实数据高度优化。7. 算法思维从解题到创造7.1 五大经典算法思想┌─────────────────────────────────────────────────────┐ │ 1. 枚举暴力 │ │ 尝试所有可能保证正确性 │ │ 例密码破解、全排列 │ ├─────────────────────────────────────────────────────┤ │ 2. 分治Divide and Conquer │ │ 大问题拆成小问题分别解决后合并 │ │ 例归并排序、快速排序、二分查找 │ ├─────────────────────────────────────────────────────┤ │ 3. 贪心Greedy │ │ 每一步选当前最优期望全局最优 │ │ 例找零钱、活动安排、最小生成树 │ ├─────────────────────────────────────────────────────┤ │ 4. 动态规划Dynamic Programming │ │ 大问题依赖子问题子问题重叠记忆化存储 │ │ 例斐波那契、背包问题、最长公共子序列 │ ├─────────────────────────────────────────────────────┤ │ 5. 回溯Backtracking │ │ 深度搜索剪枝试探性解决问题 │ │ 例八皇后、迷宫、数独、全排列 │ └─────────────────────────────────────────────────────┘7.2 算法思维训练从怎么做到为什么初级知道怎么做# 题目两数之和deftwo_sum(nums,target):foriinrange(len(nums)):forjinrange(i1,len(nums)):ifnums[i]nums[j]target:return[i,j]return[]# 能跑但 O(n²)进阶知道为什么慢# 优化用哈希表O(n)deftwo_sum_optimized(nums,target):seen{}fori,numinenumerate(nums):complementtarget-numifcomplementinseen:return[seen[complement],i]seen[num]ireturn[]# 用空间换时间从 O(n²) 降到 O(n)高级知道还能不能更好# 如果数组已排序双指针O(n)空间 O(1)deftwo_sum_sorted(nums,target):left,right0,len(nums)-1whileleftright:snums[left]nums[right]ifstarget:return[left,right]elifstarget:left1else:right-1return[]算法思维的核心面对问题先想最优解是什么再想怎么实现而不是先写出来再说。8. 结语算法之美“算法 数据结构 程序”—— Niklaus Wirth图灵奖得主算法不是冰冷的代码它是人类智慧的结晶。当你写出第一个二分查找你会惊叹原来可以这么快当你理解动态规划你会感叹子问题重叠的优雅当你解决汉诺塔你会震撼递归分解的力量为什么每个人都该学算法训练逻辑思维像计算机一样严谨思考提升问题解决能力面对复杂问题不再无从下手打开职业大门技术面试的通行证理解世界推荐系统、导航、AI 背后的原理纯粹的智力愉悦就像解出一道数学难题最后的话算法学习没有捷径但有方法。不要畏惧困难每一道你攻克的题目都在重塑你的大脑。从今天开始每天进步一点点一年后你会感谢现在的自己。记住看懂 ≠ 会写会写 ≠ 熟练熟练 ≠ 创新从模仿到创造从练习到精通。算法之路始于足下。