Agentic AI时代,程序员必备的算法思想指南
AI已来,程序员要失业了吗?别慌!Agentic AI时代,程序员最重要的不是写代码,而是教会AI如何思考 。有了Agent智能体,更需要掌握算法思想------这是你驾驭AI的"超能力"。
AI时代,程序员的价值不在于写代码,而在于用算法思想驱动AI生成最优的代码。我是刀法如飞。
目录
一、算法与算法思想概述
什么是算法?
graph TD A["什么是算法?"] --> B["输入\n问题的数据"] A --> C["输出\n问题的解"] A --> D["清晰的指令\n一系列确定的步骤"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#534AB7,stroke:#3C3489,color:#ffffff style D fill:#D85A30,stroke:#993C1D,color:#ffffff
算法是计算机解决问题的一步步的方法和步骤。它是一个确定的、有限的、有效的计算过程,包括:
工程师视角:计算机程序=算法+数据结构,算法是代码的灵魂。同样的功能,不同算法的性能差异可能是数个数量级。
什么是算法思想?
graph TD A["什么是算法思想?"] --> B["抽象和总结\n对多个具体算法的提炼"] A --> C["思维方式\n思考·分析·设计算法"] A --> D["通用方法论\n不依赖特定编程语言"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#534AB7,stroke:#3C3489,color:#ffffff style D fill:#D85A30,stroke:#993C1D,color:#ffffff
算法思想 是指解决问题的通用的、系统的方法和理念。它是对具体算法的抽象和总结 ,也是一种思考问题、分析问题、解决问题的思维方式和通用方法论。
算法与算法思想的关键区别:
- 算法思想 :抽象、通用、可复用 → 黑盒思维
- 具体算法 :实现、特定、一次性 → 白盒实现
为什么程序员必须学算法思想?
AI时代下,程序员的职责已经发生转变,程序员必须学会利用AI来生成代码。要想利用好AI就得用到算法思想。
graph TB subgraph trad["传统时代"] A1[需求] --> A2[设计算法] A2 --> A3[手写代码] A3 --> A4[测试] A4 --> A5[上线] end D[从如何编码到-如何指导-再到如何驱动] subgraph ai["AI时代"] B1[需求] --> B2[理解问题] B2 --> B3[指导AI] B3 --> B4[验证算法] B4 --> B5[上线] end trad --> D --> ai style trad fill:#F8DCDC,stroke:#333,color:#333 style ai fill:#d7f7d7,stroke:#333,color:#333 style A1 fill:#D85A30,stroke:#333,color:#ffffff style A2 fill:#D85A30,stroke:#333,color:#ffffff style A3 fill:#D85A30,stroke:#333,color:#ffffff style A4 fill:#D85A30,stroke:#333,color:#ffffff style A5 fill:#D85A30,stroke:#33,color:#ffffff style B1 fill:#1D9E75,stroke:#333,color:#ffffff style B2 fill:#1D9E75,stroke:#333,color:#ffffff style B3 fill:#1D9E75,stroke:#333,color:#ffffff style B4 fill:#1D9E75,stroke:#333,color:#ffffff style B5 fill:#1D9E75,stroke:#333,color:#ffffff style D fill:#333,stroke:#333,color:#ffffff
AI时代学算法思想的核心理由
| 理由 | 说明 | |
|---|---|---|
| 1 | 引导AI生成正确代码 | AI擅长生成代码但不擅长选择算法结构,告诉它用分治还是贪心,结果差异巨大 |
| 2 | 验证AI生成代码 | AI代码不完全可靠,还是要人来判断时间复杂度、边界条件以及成本开销等 |
| 3 | 性能优化决策 | 同一问题O(n²)和O(n log n)在千万级数据下差距是分钟级vs毫秒级,你要能决策 |
| 4 | 解决创新问题 | 新业务场景AI无从参考,用基础算法思想引领AI从零拆解问题,设计技术方案 |
| 5 | 理解系统底层 | 看懂数据库索引、缓存策略、消息队列背后的算法原理,才能在AI给出方案时判断对错 |
| 6 | 评估方案可行性 | 一个O(n²)的方案在1万条数据时没问题,在1亿条时会崩溃,这个判断AI给不了你 |
二、算法要解决什么问题?
算法要解决的问题就是现实中要解决的问题,下面列出一些主要问题分类。
graph TD ROOT["算法问题分类"] ROOT --> A["计算问题"] ROOT --> B["搜索问题"] ROOT --> C["排序问题"] ROOT --> D["优化问题"] ROOT --> E["组合问题"] ROOT --> F["图论问题"] style ROOT fill:#444441,stroke:#2C2C2A,color:#ffffff style A fill:#1D9E75,stroke:#0F6E56,color:#ffffff style B fill:#534AB7,stroke:#3C3489,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#BA7517,stroke:#854F0B,color:#ffffff style E fill:#185FA5,stroke:#0C447C,color:#ffffff style F fill:#993556,stroke:#72243E,color:#ffffff
| 问题类型 | 别名 | 典型应用 | 现实场景 | |
|---|---|---|---|---|
| 1 | 计算问题 | 求值问题 | 数值计算、统计计算 | 广告CTR/CVR预估、短视频播放完成率计算、电商订单金额结算 |
| 2 | 搜索问题 | 查找问题 | 数据库查询、倒排索引 | 电商商品关键词搜索、外卖菜单实时检索、地图POI点位查找 |
| 3 | 排序问题 | 整序问题 | 排序算法、优先级队列 | Feed流内容排序、电商搜索结果排序、外卖骑手任务优先级 |
| 4 | 优化问题 | 最优化问题 | 资源分配、最优策略 | 广告RTB实时竞价出价优化、外卖骑手路线规划、CDN节点流量分配 |
| 5 | 组合问题 | 枚举问题 | 组合生成、子集枚举 | 电商满减券组合计算、点餐套餐搭配、广告素材创意组合 |
| 6 | 图论问题 | 关系问题 | 最短路径、社交网络 | 地图最短路径导航、SNS关注链内容推荐、电商社交裂变传播 |
三、算法思想有什么作用?
通过算法思想,可以将模糊的业务问题转化为可量化、可优化的计算模型,在设计阶段就做出正确的方向选择。
graph TD A[模糊业务问题] --> B[算法思想分析] B --> C[可量化计算模型] C --> D[正确方向选择] D --> E[最优解决方案] B --> B1[问题类型识别] B --> B2[算法思想选择] B --> B3[复杂度预估] style A fill:#333,stroke:#ccc,color:#fff style B fill:#ffcc99,stroke:#ff8c00 style C fill:#99ccff,stroke:#0066cc style D fill:#b6e3a8,stroke:#2e8b57 style E fill:#66b366,stroke:#00cc00 style B1 fill:#f5bee4,stroke:#6c4374 style B2 fill:#f5bee4,stroke:#6c4374 style B3 fill:#f5bee4,stroke:#6c4374
算法思想的应用场景有很多,下面列举几个常见的例子。实际应用中这些场景往往更复杂,需要结合不同的算法思想和策略才能有效解决问题。
graph TD ROOT["算法思想的应用场景"] ROOT --> A["快速问题识别\n与方案选择"] ROOT --> B["代码性能优化"] ROOT --> C["系统架构理解"] ROOT --> D["AI编程时代\n核心竞争力"] ROOT --> E["建立通用\n解题框架"] style ROOT fill:#444441,stroke:#2C2C2A,color:#ffffff style A fill:#1D9E75,stroke:#0F6E56,color:#ffffff style B fill:#534AB7,stroke:#3C3489,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#BA7517,stroke:#854F0B,color:#ffffff style E fill:#185FA5,stroke:#0C447C,color:#ffffff
| 应用场景 | 核心要点 | |
|---|---|---|
| 1 | 快速问题识别与方案选择 | 识别问题类型(搜索/优化/排序)→ 关联对应思想(贪心/DP/分治)→ 预估复杂度 → 选择最优方案 |
| 2 | 代码性能优化 | 分析性能瓶颈,从O(n²)优化到O(n log n),在大规模数据处理中显著提升性能 |
| 3 | 系统架构理解 | 数据库索引(二分查找)、缓存淘汰(贪心)、分布式共识(图论)、操作系统调度(动态规划) |
| 4 | AI编程时代的核心竞争力 | 用算法思想引导AI生成正确代码,验证代码正确性与最优性,优化AI生成方案 |
| 5 | 建立通用解题框架 | 面对新问题有章可循,知道何时用何种方法,能组合多种思想解决复杂问题 |
Agent Skill需要算法思想指引
在Agentic时代,Agent 的每个执行环节------感知、推理规划、行动执行------都需要提前编写对应的 Skill,将解决问题的策略预置给 AI。
这正是程序员核心价值所在:理解业务本质,用算法思想制定推理和执行策略,让 Agent 真正完成任务。 没有扎实的算法思想基础,Skill 只是空壳,Agent 也只是在执行指令而非解决问题。
graph LR GOAL["目标\nTask"] --> A A["感知\n获取环境数据和上下文"] A --> B["推理与规划\n分析状态\n检索记忆\n制定计划"] B --> C["行动执行\n调用工具\n访问API\n执行子任务"] C --> D["观察与反馈\n评估结果\n与目标对比"] D --> E["学习与迭代\n更新记忆\n优化策略"] E -->|"未完成,继续循环"| A E -->|"目标达成"| DONE["输出结果\nDone"] style GOAL fill:#444441,stroke:#2C2C2A,color:#ffffff style A fill:#1D9E75,stroke:#0F6E56,color:#ffffff style B fill:#534AB7,stroke:#3C3489,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#BA7517,stroke:#854F0B,color:#ffffff style E fill:#185FA5,stroke:#0C447C,color:#ffffff style DONE fill:#993556,stroke:#72243E,color:#ffffff
四、算法思想大全
常见的5大核心思想与2大策略
相关算法思想及源码请见:https://github.com/microwind/algorithms
graph TD A["算法思想"] --> B1["贪心\nGreedy"] A --> B2["分治\nDivide & Conquer"] A --> B3["动态规划\nDynamic Programming"] A --> B4["回溯\nBacktracking"] A --> B5["分支限界\nBranch and Bound"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B1 fill:#1D9E75,stroke:#0F6E56,color:#ffffff style B2 fill:#534AB7,stroke:#3C3489,color:#ffffff style B3 fill:#D85A30,stroke:#993C1D,color:#ffffff style B4 fill:#BA7517,stroke:#854F0B,color:#ffffff style B5 fill:#185FA5,stroke:#0C447C,color:#ffffff
graph TD A["算法策略"] --> C1["随机化\nRandomized Algorithms"] A --> C2["搜索策略\nSearch Strategies"] A["算法策略"] --> D1["其他......"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style C1 fill:#993556,stroke:#72243E,color:#ffffff style C2 fill:#3B6D11,stroke:#27500A,color:#ffffff style D1 fill:#0F6E56,stroke:#3C3489,color:#ffffff
算法思想 就像"武功秘籍",是解决问题的设计思路,通过不同的分解和递推方式来处理复杂问题,下面将详细介绍具体算法思想与策略。
1 贪心算法 (Greedy)-- "步步最优"的策略
| 核心思想 | 算法特征 | 适用场景 | 常见应用 |
|---|---|---|---|
| 每一步都选择当前状态下的最优选择,期望得到全局最优解 | 贪心选择性 :全局最优解可以通过局部最优选择得到 最优子结构 :问题的最优解包含子问题的最优解 无后效性:前面的选择不影响后面的决策 | 最优子结构明显的问题 无后效性的决策 实时性要求高的系统 | 1. 活动选择、区间调度 2. 霍夫曼编码、最小生成树 3. 任务调度 |
贪心算法流程图
graph LR A["初始化:候选集合"] --> B["选择最优候选"] B --> C["做出贪心选择"] C --> D["更新问题规模"] D --> E["还有候选?"] E -->|是| B E -->|否| F["输出最优解"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#534AB7,stroke:#3C3489,color:#ffffff style E fill:#BA7517,stroke:#854F0B,color:#ffffff style F fill:#185FA5,stroke:#0C447C,color:#ffffff
伪代码示例(活动选择问题)
c
function SelectActivities(activities):
// 按活动结束时间排序
sort(activities by end_time)
selected = [activities[0]]
last_end = activities[0].end_time
// 遍历活动,选择不冲突的活动
for i = 1 to len(activities):
// 如果当前活动开始时间晚于上一个活动结束时间,选择当前活动
if activities[i].start_time >= last_end:
selected.append(activities[i])
// 更新上一个活动结束时间
last_end = activities[i].end_time
return selected
2 分治算法 (Divide and Conquer)--"分而治之"的艺术
| 核心思想 | 三个阶段 | 算法特征 | 适用场景 | 常见应用 |
|---|---|---|---|---|
| 分解问题 → 递归求解子问题 → 合并子问题的结果 | Divide :把问题分解成若干个规模较小的相同问题 Conquer :递归求解这些子问题 Combine:合并子问题的解成原问题的解 | 自相似性 :问题可以被分解为相似的子问题 独立性 :子问题相互独立 并行性:可以并行处理子问题 | 问题具有自相似性 子问题相互独立 需要处理大规模数据 | 1. 排序(快速排序、归并排序) 2. 二分查找、矩阵乘法 3. 并行计算 |
分治算法流程图
graph LR A["原问题"] --> B["分解"] B --> C["子问题1"] B --> D["子问题2"] B --> E["子问题N"] C --> F["递归求解"] D --> F E --> F F --> G["子问题解"] G --> H["合并"] H --> I["最终解"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#D85A30,stroke:#993C1D,color:#ffffff style C fill:#1D9E75,stroke:#0F6E56,color:#ffffff style D fill:#1D9E75,stroke:#0F6E56,color:#ffffff style E fill:#1D9E75,stroke:#0F6E56,color:#ffffff style F fill:#534AB7,stroke:#3C3489,color:#ffffff style G fill:#534AB7,stroke:#3C3489,color:#ffffff style H fill:#BA7517,stroke:#854F0B,color:#ffffff style I fill:#185FA5,stroke:#0C447C,color:#ffffff
伪代码示例(归并排序)
c
function MergeSort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) / 2
// 递归分解左右子数组
left = MergeSort(arr[0:mid]) // 分解
right = MergeSort(arr[mid:]) // 治理
return Merge(left, right) // 合并
function Merge(left, right):
result = []
i = j = 0
// 合并两个有序数组,循环比较两个子数组的当前元素,选择较小的一个
while i < len(left) and j < len(right):
// 如果左子数组的当前元素较小,则选择左子数组的当前元素,同时移动左指针
if left[i] <= right[j]:
result.append(left[i])
i += 1
// 否则,选择右子数组的当前元素,同时移动右指针
else:
result.append(right[j])
j += 1
return result + left[i:] + right[j:]
3 动态规划 (Dynamic Programming)--"以空间换时间"的法则
| 核心思想 | 必要条件 | 实现方式 | 适用场景 | 常见应用 |
|---|---|---|---|---|
| 以空间换时间,用记忆化消除重复计算 | 最优子结构 :大问题的最优解 = 子问题最优解的组合 重叠子问题:不同的子问题有重复计算 | 自顶向下 :记忆化递归 自底向上:递推表格 | 最优子结构+重叠子问题 多阶段决策问题 优化问题(求最大值、最小值、方案数) | 1. 背包问题、币种兑换 2. 最长递增子序列、编辑距离 3. 路径计数 |
动态规划流程图
graph LR A["问题分析\n最优子结构+重叠子问题"] --> B["建模\n1. 定义状态\n 2. 状态转移方程"] B --> C["求解\n 1. 初始化\n 2. 自底向上递推\n 3. 填充DP表"] C --> D["输出\n 1. 查询结果\n 2. 回溯求解\n 3. 输出最优解"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#534AB7,stroke:#3C3489,color:#ffffff style D fill:#993556,stroke:#72243E,color:#ffffff
伪代码示例(0-1背包问题 - 自底向上)
c
function KnapsackDP(weights, values, capacity):
n = len(weights)
// 初始化dp数组,dp[i][w]表示前i件物品在容量为w时的最大价值
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
for i = 1 to n: // 遍历物品
for w = 1 to capacity: // 遍历容量
// 如果当前物品的重量不超过当前容量,考虑是否选择当前物品
if weights[i-1] <= w:
// 状态转移方程:dp[i][w] = max(不选当前物品, 选当前物品)
dp[i][w] = max(
dp[i-1][w],
dp[i-1][w-weights[i-1]] + values[i-1]
)
// 否则,当前物品不选,继承前一个物品的最大价值
else:
dp[i][w] = dp[i-1][w]
return dp[n][capacity]
4 回溯算法 (Backtracking)--"试错探索"的精神
| 核心思想 | 本质 | 关键步骤 | 适用场景 | 常见应用 |
|---|---|---|---|---|
| 尝试 → 探索 → 回退,系统地尝试所有可能性直到找到解 | 带约束的深度优先搜索(DFS) | 1. 做出选择 2. 在这个选择上进行递归 3. 撤销选择(回退) 4. 尝试其他选择 | 需要枚举所有可能解 组合生成、排列问题 约束满足问题 | 1. 全排列、组合生成 2. N皇后问题 3. 数独求解 |
回溯算法流程图
graph LR A["开始:初始状态"] --> B["做出选择"] B --> C["检查约束"] C -->|满足| D["递归探索"] C -->|不满足| E["回退"] D --> F["找到解?"] F -->|是| G["记录解"] F -->|否| B G --> E E --> H["还有选择?"] H -->|是| B H -->|否| I["输出所有解"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#534AB7,stroke:#3C3489,color:#ffffff style E fill:#BA7517,stroke:#854F0B,color:#ffffff style F fill:#BA7517,stroke:#854F0B,color:#ffffff style G fill:#185FA5,stroke:#0C447C,color:#ffffff style H fill:#185FA5,stroke:#0C447C,color:#ffffff style I fill:#993556,stroke:#72243E,color:#ffffff
伪代码示例(全排列问题)
c
function Permutations(arr, start, result):
if start == len(arr) - 1:
result.append(copy(arr)) // 找到一个排列
return
// 从当前位置开始,尝试将每个元素交换到当前位置
for i = start to len(arr) - 1:
swap(arr[start], arr[i]) // 做出选择(交换当前元素到当前位置)
Permutations(arr, start + 1, result) // 在这个选择上进行递归
swap(arr[start], arr[i]) // 撤销选择(回退),恢复之前的状态
function GetPermutations(arr):
result = []
Permutations(arr, 0, result)
return result
5 分支限界算法 (Branch and Bound)--"剪枝优化"的技巧
| 核心思想 | 算法特点 | 适用场景 | 常见应用 |
|---|---|---|---|
| 通过剪枝来减少搜索空间,在回溯的基础上加入界限函数 | 分支 :将问题分解为子问题 限界 :计算子问题的界限,剪枝不可能产生最优解的分支 剪枝:提前终止不可能产生最优解的搜索路径 | 搜索空间巨大的优化问题 需要找到全局最优解 可以计算上下界的问题 | 1. 旅行商问题 2. 背包问题优化 3. 任务调度、资源分配 |
分支限界流程图
graph LR A["初始化:队列+最优值"] --> B["队列非空?"] B -->|是| C["取出节点"] C --> D["计算上界"] D --> E["上界>最优值?"] E -->|是| G["分支:生成子节点"] E -->|否| F["剪枝"] G --> H["更新最优值"] H --> I["加入队列"] I --> B F --> B B -->|否| J["输出最优解"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#BA7517,stroke:#854F0B,color:#ffffff style C fill:#1D9E75,stroke:#0F6E56,color:#ffffff style D fill:#D85A30,stroke:#993C1D,color:#ffffff style E fill:#D85A30,stroke:#993C1D,color:#ffffff style F fill:#993556,stroke:#72243E,color:#ffffff style G fill:#534AB7,stroke:#3C3489,color:#ffffff style H fill:#185FA5,stroke:#0C447C,color:#ffffff style I fill:#185FA5,stroke:#0C447C,color:#ffffff style J fill:#0F6E56,stroke:#3C3489,color:#ffffff
伪代码示例(0-1背包问题 - 分支限界)
c
function KnapsackBranchBound(weights, values, capacity):
best_value = 0
// 初始化队列,包含初始节点(容量、当前价值、当前物品索引)
queue = [InitialNode(capacity, 0, 0)]
// 循环处理队列中的节点,直到队列为空
while queue is not empty:
node = queue.pop()
if node.bound < best_value: // 剪枝:上界小于当前最优
continue
// 子循环:遍历当前节点的所有子节点(选择当前物品或不选)
for each item i:
new_weight = node.weight + weights[i]
new_value = node.value + values[i]
// 如果当前物品的重量不超过当前容量,考虑是否选择当前物品
if new_weight <= capacity:
best_value = max(best_value, new_value)
upper_bound = CalculateUpperBound(new_value, new_weight, ...)
// 计算上界:当前价值 + 剩余物品的最大价值上界
if upper_bound > best_value: // 限界:有希望得到更优解
queue.append(NewNode(new_weight, new_value, upper_bound))
return best_value
6 随机化算法 (Randomized Algorithms)--"以概率换效率"的魔法
| 核心思想 | 算法类型 | 算法特征 | 适用场景 | 常见应用 |
|---|---|---|---|---|
| 利用随机性来简化算法设计、提高性能或解决确定性算法难以处理的问题 | 拉斯维加斯算法 :总是给出正确答案,但运行时间随机 蒙特卡洛算法:运行时间确定,但可能给出错误答案 | 随机性 :利用随机数或随机过程 概率性 :结果具有概率保证 简化性:随机化可以简化算法设计 | 需要避免被识别的系统 性能要求高但可接受近似解 确定性算法过于复杂的问题 | 1. 爬虫调度 2. A/B测试 3. 缓存过期时间随机化 |
随机化算法流程图
graph LR A["问题"] --> B["引入随机性"] B --> C["随机选择"] C --> D["执行算法"] D --> E["得到结果"] E --> F["验证结果"] F --> G["结果正确?"] G -->|是| H["输出结果"] G -->|否| I["重新执行"] I --> C style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#534AB7,stroke:#3C3489,color:#ffffff style E fill:#BA7517,stroke:#854F0B,color:#ffffff style F fill:#BA7517,stroke:#854F0B,color:#ffffff style G fill:#185FA5,stroke:#0C447C,color:#ffffff style H fill:#0F6E56,stroke:#3C3489,color:#ffffff style I fill:#993556,stroke:#72243E,color:#ffffff
伪代码示例(随机快速选择 - 拉斯维加斯算法)
c
function RandomSelect(arr, k): // 找第k小元素
// 随机选择一个 pivot 元素
pivot_idx = RandomPartition(arr, 0, len(arr) - 1)
// 如果 pivot 的位置正好是 k-1,说明找到了第 k 小元素
if pivot_idx == k - 1:
return arr[pivot_idx]
// 如果 pivot 的位置小于 k-1,说明第 k 小元素在 pivot 的右侧,继续在右侧子数组中寻找
elif pivot_idx < k - 1:
return RandomSelect(arr[pivot_idx + 1:], k - pivot_idx - 1)
// 如果 pivot 的位置大于 k-1,说明第 k 小元素在 pivot 的左侧,继续在左侧子数组中寻找
else:
return RandomSelect(arr[:pivot_idx], k)
function RandomPartition(arr, left, right):
// 随机选择一个 pivot 元素的索引
random_idx = Random(left, right)
swap(arr[right], arr[random_idx])
pivot = arr[right]
i = left - 1
// 遍历数组,将小于 pivot 的元素交换到左侧
for j = left to right - 1:
// 如果当前元素小于 pivot,将其交换到左侧
if arr[j] < pivot:
i += 1
swap(arr[i], arr[j])
// 将 pivot 交换到正确位置
swap(arr[i + 1], arr[right])
return i + 1
7 搜索策略 (Search Strategies)--"系统探索"的方法
| 核心思想 | 策略分类 | 结合使用 | 适用场景 | 常见应用 |
|---|---|---|---|---|
| 系统性地在解空间中搜索目标,不同的策略适用于不同类型的问题 | BFS :广度优先搜索,逐层扩展 DFS :深度优先搜索,一路到底 A :启发式搜索,有指导的搜索 IDDFS*:迭代加深DFS,结合BFS和DFS优点 | BFS/DFS :常与回溯、分支限界结合 A*:用于路径规划和启发式优化 | 需要在解空间中找到目标 路径规划和优化问题 需要遍历复杂解空间 | 1. 最短路径、社交网络推荐 2. 导航系统 3. 图遍历 |
搜索策略流程图
graph LR A["初始化:起点"] --> B["选择策略"] B --> C{策略类型} C -->|BFS| D["队列:FIFO"] C -->|DFS| E["栈:LIFO"] C -->|A*| F["优先队列:启发式"] D --> G["取出节点"] E --> G F --> G G --> H["是目标?"] H -->|是| I["返回路径"] H -->|否| J["扩展邻居"] J --> K["加入容器"] K --> L["容器非空?"] L -->|是| G L -->|否| M["搜索失败"] style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#534AB7,stroke:#3C3489,color:#ffffff style E fill:#534AB7,stroke:#3C3489,color:#ffffff style F fill:#534AB7,stroke:#3C3489,color:#ffffff style G fill:#BA7517,stroke:#854F0B,color:#ffffff style H fill:#BA7517,stroke:#854F0B,color:#ffffff style I fill:#185FA5,stroke:#0C447C,color:#ffffff style J fill:#185FA5,stroke:#0C447C,color:#ffffff style K fill:#185FA5,stroke:#0C447C,color:#ffffff style L fill:#BA7517,stroke:#854F0B,color:#ffffff style M fill:#993556,stroke:#72243E,color:#ffffff
伪代码示例(BFS - 广度优先搜索)
c
function BFS(graph, start):
queue = [start]
visited = {start}
result = []
// 循环处理队列中的节点,直到队列为空
while queue is not empty:
node = queue.pop_front() // 取队列首元素
result.append(node) // 记录当前节点
for neighbor in graph[node]: // 逐层扩展
if neighbor not in visited: // 如果邻居未被访问过
visited.add(neighbor) // 标记为已访问
queue.append(neighbor) // 加入队列,继续扩展
return result
function BFSShortest(graph, start, end): // 求最短路径
queue = [(start, [start])]
visited = {start}
// 循环处理队列中的节点,直到队列为空
while queue is not empty:
node, path = queue.pop_front()
if node == end:
return path
// 遍历当前节点的邻居
for neighbor in graph[node]:
// 如果邻居未被访问过,将其加入队列,并标记为已访问
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, path + [neighbor]))
return None
算法思想源码资料请见 https://github.com/microwind/algorithms
五、算法思想指导AI编程实战
AI Agent代码生成流程
graph LR A["业务需求"] --> B["Planning\n问题分析·任务分解·算法选择"] B --> C["Skill设计\n感知·推理·行动·反馈"] C --> D["AI执行\n生成代码·调用工具·完成任务"] D --> E["Observation\n验证结果·评估质量"] E -->|"通过"| F["上线迭代"] E -->|"不通过"| B style A fill:#444441,stroke:#2C2C2A,color:#ffffff style B fill:#1D9E75,stroke:#0F6E56,color:#ffffff style C fill:#534AB7,stroke:#3C3489,color:#ffffff style D fill:#D85A30,stroke:#993C1D,color:#ffffff style E fill:#BA7517,stroke:#854F0B,color:#ffffff style F fill:#185FA5,stroke:#0C447C,color:#ffffff
详见文档:AI Agent代码生成系统完全指南
实战案例1:电商秒杀系统(贪心算法)
业务需求
高并发商品抢购,确保公平性和系统稳定性
算法建模
| 问题抽象 | 算法思想 | 核心思路 |
|---|---|---|
| 资源分配 + 顺序决策 | 贪心算法(队列 + 贪心选择) | 每个请求立即做最优分配 |
指导AI编程
AI,请实现贪心算法的秒杀系统:
1. 用户请求进入队列
2. 按队列顺序处理(贪心选择)
3. 检查库存和用户限制
4. 立即分配或拒绝
SKILL模板:秒杀系统贪心分配
yaml
SKILL: FlashSaleGreedyAllocation
描述: 使用贪心算法实现高并发秒杀系统的库存分配
输入:
- user_requests: 用户请求队列 (FIFO)
- inventory: 商品库存数量
- user_limits: 每个用户的购买限制
处理流程:
1. 初始化: 创建请求队列,设置库存计数器
2. 贪心选择: 按队列顺序逐个处理请求
3. 检查约束: 验证库存充足 && 用户未超限
4. 立即决策: 满足条件则分配,否则拒绝
5. 更新状态: 库存-1,用户购买数+1
输出:
- allocation_result: {user_id, status, quantity}
- remaining_inventory: 剩余库存
- user_purchase_record: 用户购买记录
复杂度:
- 时间: O(n) - n为请求数
- 空间: O(n) - 存储请求和记录
实战案例2:视频内容分发(分治算法)
业务需求
全球用户低延迟视频播放,优化传输成本
算法建模
| 问题抽象 | 算法思想 | 核心思路 |
|---|---|---|
| 大规模数据分发 + 地理位置优化 | 分治算法 | Divide(地理分组)→ Conquer(并行分发)→ Combine(结果合并) |
指导AI编程
AI,请实现分治算法的视频分发:
1. Divide:按地理位置将用户分组
2. Conquer:并行处理各组的视频分发
3. Combine:合并分发状态和结果
4. 优化:选择最近的CDN节点
SKILL模板:视频分发分治系统
yaml
SKILL: VideoDistributionDivideConquer
描述: 使用分治算法实现全球视频内容的低延迟分发
输入:
- users: 全球用户列表 {user_id, region, location}
- video_content: 视频文件信息
- cdn_nodes: CDN节点列表 {node_id, region, capacity}
处理流程:
1. Divide: 按地理区域递归分组用户
- 分组策略: 按大陆/国家/城市分层
- 递归条件: 直到组内用户数<阈值
2. Conquer: 并行处理各组分发
- 为每组选择最近CDN节点
- 并行推送视频到各CDN
- 各组独立处理,互不影响
3. Combine: 合并分发结果
- 收集各组分发状态
- 汇总成功/失败统计
- 生成全局分发报告
输出:
- distribution_status: {region, success_count, fail_count}
- cdn_utilization: 各CDN节点利用率
- latency_metrics: 各地区平均延迟
复杂度:
- 时间: O(n log n) - n为用户数
- 空间: O(n) - 递归栈+临时数据
实战案例3:外卖路径优化(动态规划)
业务需求
规划最优配送路线,提高配送效率和用户体验
算法建模
| 问题抽象 | 算法思想 | 核心思路 |
|---|---|---|
| 多阶段决策优化 + 资源约束 | 动态规划 | 当前最优 = 之前最优 + 当前决策 |
指导AI编程
AI,请实现动态规划的配送优化:
1. 状态定义:(当前订单集合, 当前时间, 当前位置)
2. 状态转移:尝试每个订单作为下一个配送目标
3. 记忆化:缓存已计算的状态结果
4. 回溯:基于DP结果重构最优路径
SKILL模板:外卖路径优化动态规划
yaml
SKILL: DeliveryRouteOptimizationDP
描述: 使用动态规划实现外卖配送路线的最优规划
输入:
- orders: 待配送订单列表 {order_id, location, deadline}
- current_location: 骑手当前位置
- current_time: 当前时间
- distance_matrix: 位置间距离矩阵
处理流程:
1. 状态定义: dp[mask][i][t]
- mask: 已配送订单的位掩码
- i: 当前位置索引
- t: 当前时间
- 值: 最小配送时间/最大满意度
2. 状态转移方程:
dp[mask][i][t] = min(
dp[mask|1<<j][j][t+distance[i][j]]
for j in unvisited_orders
if t+distance[i][j] <= deadline[j]
)
3. 记忆化:
- 使用哈希表缓存已计算状态
- 避免重复计算相同子问题
4. 回溯求解:
- 从最优状态反向追踪
- 记录每步的最优选择
- 构建完整配送路径
输出:
- optimal_route: [order_id1, order_id2, ...]
- total_time: 总配送时间
- satisfaction_score: 用户满意度评分
- route_visualization: 路线可视化数据
复杂度:
- 时间: O(2^n * n^2) - n为订单数
- 空间: O(2^n * n) - DP表存储
本文相关skills请见: https://github.com/microwind/ai-skills
六、程序员如何学习算法思想?
程序员的三层能力模型
AI时代,掌握这三层能力,你就能驾驭AI,让AI替你打工。
graph LR A[业务需求] --> B[1. 描述需求 What] B --> C[2. 定义边界 Scope] C --> D[3. 算法建模 How] D --> E[AI实现] B --> B1[清晰业务问题] C --> C1[明确约束条件] D --> D1[用思想指导AI] style A fill:#333,stroke:#000,color:#ffffff style B fill:#534AB7,stroke:#3C3489,color:#ffffff style C fill:#D85A30,stroke:#993C1D,color:#ffffff style D fill:#BA7517,stroke:#854F0B,color:#ffffff style E fill:#1D9E75,stroke:#3C3489,color:#ffffff
| 层级 | 核心问题 | 关键要素 | 示例 |
|---|---|---|---|
| 第一层:描述需求(What) | 要解决什么业务问题? | 清晰描述业务目标 | ✗ "写一个推荐系统" ✓ "给用户推荐他们可能感兴趣的商品" |
| 第二层:定义边界(Scope) | 问题的规模和限制是什么? | 数据规模 :用户数、商品数、请求数 性能要求 :响应时间、处理时间 资源约束 :内存、CPU、网络带宽 质量要求:准确率、成功率、容错性 | 用户数/商品数/请求数、响应时间、内存CPU、准确率容错性 |
| 第三层:算法建模(How) | 用什么算法模型解决? | 问题抽象→模型选择→指导AI 问题抽象 :将业务问题转化为算法问题 模型选择 :基于约束选择合适的算法思想 指导AI:用算法思想指导AI生成代码 | 推荐问题→向量相似度搜索→KNN/ANN算法→AI实现 |
AI编程指导原则
| 规则 | 核心要点 | |
|---|---|---|
| 1 | 用思想而不是需求驱动AI | ✗ "给我一个搜索函数" ✓ "用二分查找设计搜索函数,支持O(log n)查询,处理不存在的情况" |
| 2 | 验证AI的结果 | 检查:时间复杂度是否符合预期、空间复杂度是否可接受、边界情况是否完整、是否有更优方案 |
| 3 | 理解权衡而不是盲目求最优 | 没有完美算法,只有权衡:时间vs空间、复杂度vs可维护性、最优vs足够好、通用vs特化 |
| 4 | 保持对AI代码的怀疑 | AI易出错点:复杂度分析错误、边界遗漏、逻辑漏洞、性能瓶颈、不符合业务逻辑。关键代码永远要自己验证 |
| 5 | 用小问题积累大智慧 | 小问题测试算法思想 → AI生成代码+解释 → 自己分析验证 → 迁移到大问题 → 重复循环 |
程序员认知转变
- 从"如何编码"转变为"如何设计"到"如何驱动"
- 从"实现者"升级为"指导者"或者"协调者"
- AI时代,程序员的价值在于架构设计和算法思想而非编码能力
没有算法思想的程序员,就像没有地图的探险家------AI再强大也只会原地打转。
AI时代最贵的不是代码,而是让AI写出正确代码的那个"想法"。
算法思想不是数学家的专利,而是每个程序员的"超能力"。
七、核心算法思想应用场景总结
| 思想/策略 | 核心机制 | 实际工程场景 | 生活类比 |
|---|---|---|---|
| 贪心 | 每步局部最优,逐步逼近全局最优 | 1. 电商秒杀库存分配 2. 外卖/打车实时派单 3. 抖音/微博信息流广告竞价 | 自助餐每次只夹当前最想吃的,不管后面还有什么 |
| 分治 | 分解问题递归求解,化繁为简 | 1. CDN 视频内容分发(YouTube/B站) 2. Hadoop/Spark 大数据分布式处理 3. 搜索引擎倒排索引构建 | 大项目拆分成小任务,团队并行完成 |
| 动态规划 | 记忆化消除重复计算 | 1. 滴滴/美团外卖路径规划 2. 拼多多/淘宝优惠券组合最优解 3. 微信输入法拼音联想词序列 | 做过的数学题记下答案,下次遇到直接查,不重新算 |
| 回溯 | 系统尝试 + 约束回退 | 1. 企业权限角色组合生成 2. 自动化测试用例全量覆盖 3. 游戏关卡地图自动生成 | 走迷宫,走不通就退回来换条路 |
| 分支限界 | 估算上界,剪枝搜索最优 | 1. 顺丰/菜鸟物流线路最优规划 2. 企业级网络安全漏洞扫描 3. 云平台任务调度资源最优分配 | GPS导航,提前排除不可能的路线 |
| 随机化 | 引入随机性简化问题或提升性能 | 1. 爬虫请求随机调度(反反爬) 2. A/B 测试流量随机分桶 3. Redis 缓存过期时间随机抖动(防雪崩) | 考试不会的题先跳过随机猜一个,整体效率更高 |
| 搜索策略(BFS/DFS/A*) | 系统遍历解空间,按策略选择路径 | 1. 微信社交关系六度推荐 2. 高德最优导航路径 3. 云音乐个性化推荐 | 找钥匙,系统性地检查每个角落 |