DFS的指数型枚举
指数型枚举通常涉及从一组元素中选择任意子集(包括空集),每个元素有“选”或“不选”两种状态。其核心是通过递归遍历所有可能的组合。
实现要点
-
递归函数设计
参数通常包括当前处理的位置(如数组下标)和临时存储结果的容器(如vector<int>)。void dfs(int u, vector<int>& path) { if (u > n) { // 递归终止条件:处理完所有元素 for (auto x : path) cout << x << " "; cout << endl; return; } path.push_back(u); // 选择当前元素 dfs(u + 1, path); // 递归处理下一个元素 path.pop_back(); // 回溯:不选当前元素 dfs(u + 1, path); // 递归处理下一个元素 } -
时间复杂度
每个元素有2种选择,总时间复杂度为 $O(2^n)$,空间复杂度为 $O(n)$(递归栈深度)。
应用场景
- 子集问题(如LeetCode 78. Subsets)。
- 组合问题(需限制路径长度时)。
DFS的排列型枚举
排列型枚举需生成所有可能的排列(全排列),即元素的顺序不同视为不同解。通常通过交换元素或标记访问状态实现。
实现要点
-
交换法实现
通过交换当前位置与其他位置元素生成排列。void dfs(int u, vector<int>& nums) { if (u == nums.size()) { // 终止条件:生成一个完整排列 for (auto x : nums) cout << x << " "; cout << endl; return; } for (int i = u; i < nums.size(); i++) { swap(nums[u], nums[i]); // 交换元素 dfs(u + 1, nums); // 递归处理下一个位置 swap(nums[u], nums[i]); // 回溯 } } -
标记法实现
使用visited数组记录已选元素,避免重复选择。void dfs(int u, vector<int>& path, vector<bool>& visited) { if (u > n) { for (auto x : path) cout << x << " "; cout << endl; return; } for (int i = 1; i <= n; i++) { if (!visited[i]) { visited[i] = true; path.push_back(i); dfs(u + 1, path, visited); // 注意参数为u+1,表示处理下一个位置 path.pop_back(); // 回溯 visited[i] = false; } } } -
时间复杂度
排列数为 $O(n!)$,空间复杂度为 $O(n)$(递归栈和辅助数组)。
应用场景
- 全排列问题(如LeetCode 46. Permutations)。
- 需要考虑顺序的组合问题。
关键区别
- 指数型:关注元素是否被选中,解空间为子集,时间复杂度 $O(2^n)$。
- 排列型:关注元素顺序,解空间为排列,时间复杂度 $O(n!)$。
两种枚举方式均需注意剪枝优化(如提前终止不符合条件的路径)以提升效率。
5142

被折叠的 条评论
为什么被折叠?



