1. 基本概念

核心定义

枚举算法是一种通过逐一尝试所有可能情况来解决问题的算法策略。它不依赖复杂的逻辑推理,而是依靠计算机的高速运算能力,将问题的所有解或可能的解一一列举出来,然后根据约束条件筛选出符合条件的解。

核心思想

“宁可错杀一千,不可放过一个”。通过循环遍历所有候选解,逐一验证。

适用场景

  • 问题规模较小,解空间有限
  • 无法找到更高效的优化算法(如某些NP难问题)
  • 作为验证其他高效算法正确性的"基准测试(Ground Truth)"

2. 算法核心步骤

枚举算法的执行过程可以严格拆解为以下4个标准步骤:

步骤序号 步骤名称 核心操作描述 关键问题
Step 1 确定解空间 明确问题的"搜索范围"。即确定哪些数据是候选解,以及它们的排列方式(如数组、集合、排列组合)。 “我要在哪些数据里找?”
Step 2 设计循环结构 根据解空间的维度,构建嵌套循环(For/While)。如果是多维解(如矩阵),通常需要多层循环嵌套。 “我该怎么遍历所有情况?”
Step 3 验证约束条件 在循环体内,编写If语句判断当前候选解是否满足题目要求(如a + b == target)。 “这个当前的值符合要求吗?”
Step 4 记录并输出 如果满足条件,执行记录操作(如存入列表、更新最大值);如果不满足,继续下一次循环。 “符合了我该做什么?”

3. 费曼理解 (Feynman Technique)

想象你在找丢失的钥匙。枚举算法的做法就是:地毯式搜索。
你不会去猜钥匙在哪儿,而是从房间的左上角开始,一厘米一厘米地检查,直到找到钥匙为止。
优点:只要钥匙在房间里,你100%能找到。
缺点:如果房间很大(数据量大),这个过程会非常慢。

4. 进阶技巧:剪枝 (Pruning)

虽然标准步骤是"遍历所有",但在实际应用中,我们通常会在Step 3后面加一个剪枝操作,以提升效率。

剪枝逻辑

如果发现当前这条路肯定走不通,就提前break或continue,不再浪费时间。

示例

在求解"和大于目标值"的问题时,如果内层循环发现nums[i] + nums[j] > target,且数组已排序,那么后面的j+1, j+2...肯定更大,可以直接跳出内层循环。

1
2
3
4
if nums[i] + nums[j] == target:
return [i, j]
elif nums[i] + nums[j] > target: # 剪枝条件
break # 提前结束,不再检查后面的j

5. 应用场景

枚举算法虽然"笨",但在以下场景中不可或缺:

1. 密码学与安全

  • 暴力破解(Brute Force Attack):尝试所有可能的密码组合。这是黑客攻击的基础手段,也是验证密码强度的标准(如:8位纯数字密码约需4分钟暴力破解)。

2. 组合优化问题

  • 旅行商问题 (TSP):当城市数量较少(如<10)时,直接枚举所有路径排列并计算距离是可行的。
  • 0-1背包问题:枚举所有物品的取舍组合(2^n种),找出价值最大的组合。

3. 系统开发与调试

  • 数据校验:在小数据集上,通过双重for循环检查两个列表是否有重复项。
  • 基准测试:在开发高效算法(如KMP、DP)时,先写一个枚举算法作为"黄金标准",用来验证新算法的输出是否正确。

6. 总结

枚举算法的"哲学"

枚举算法教会我们一个重要的计算机科学真理:计算资源是有限的,而可能性是无限的。它是我们理解算法效率的起点——当你发现枚举太慢时,你就会开始寻找哈希表、动态规划或贪心算法。

7.相关

1
2
3
4
TABLE without id file.link AS "题目名称", 数据结构,date
FROM #LeetCode
WHERE contains(数据结构, "枚举")
SORT file.mtime DESC