例题一 :全排列(力扣 46 中等)
题目链接:力扣https://leetcode-cn.com/problems/permutations/
题目: 给定一个不含重复数字的数组nums, 返回其所有可能的全排列。你可以按任意顺序返回答案。
示例 1:
输入:nums = [ 1, 2, 3]
输出:[ [ 1, 2, 3], [ 1, 3, 2], [ 2, 1, 3], [ 2, 3, 1], [ 3, 1, 2], [ 3, 2, 1]]
示例 2:
输入:nums = [ 0, 1]
输出:[ [ 0, 1], [ 1, 0]]
示例 3:
输入:nums = [1]
输出:[ [ 1]]
提示:
- 1 <= nums.length <= 6
- -10 <= nums[i] <= 10
- nums中的所有整数互不相同
题目分析
先画出树形结构图:
可以通过回溯来实现全排序。在回溯中(递归结束的条件)res.size() == nums.size() ,因为是排序可以用一个数组来标记一个数是否被选取,在循环中进行排序(如果一个数被选了就继续循环, 否则将该数标记, 然后计入res,继续递归)。
代码:
class Solution {
public:
vector<vector<int>> ans;
vector<int> res;
bool visit[8];
void backstrucking(vector<int>& nums)
{
if(res.size() == nums.size())
{
ans.emplace_back(res);
return;
}
for(int i = 0; i < nums.size(); i ++)
{
if(visit[i])
{
continue;
}
visit[i] = true;
res.emplace_back(nums[i]);
backstrucking(nums);
res.pop_back();
visit[i] = false;
}
}
vector<vector<int>> permute(vector<int>& nums) {
memset(visit, false, sizeof(visit));
backstrucking(nums);
return ans;
}
};
例题二:子集(力扣 78 中等)
题目链接:力扣https://leetcode-cn.com/problems/subsets/
题目:给你一个整数数组nums, 数组中的元素互不相同。返回该数组的子集(幂集)。解集不能包含重复的子集。你可以按任意顺序返回解集。
示例 1:
输入:nums = [ 1, 2, 3]
输出:[ [ ], [ 1], [ 2], [ 1, 2], [ 3], [ 1, 3], [ 2, 3], [ 1, 2, 3]]
示例 2:
输入:nums = [ 1]
输出:[ [ ], [ 1]]
提示:
- 1 <= nums.length <= 10
- -10 <= nums[i] <= 10
- nums中所有元素互不相同
题目分析:
画出树形结构图
通过回溯实现找出子集。回溯的细节:该回溯需要通过一个下标a去查找,每次递归都直接计入数组, 在循环中(从下标a开始),每次循环都计入一个数。
代码:
class Solution {
public:
vector<int> ans;
vector<vector<int>> res;
void backstrucking(vector<int>& nums, int a)
{
res.emplace_back(ans);
for(int i = a; i < nums.size(); i ++)
{
ans.emplace_back(nums[i]);
backstrucking(nums, i + 1);
ans.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backstrucking(nums, 0);
return res;
}
};
总结:
当涉及回溯的问题时,先画出树形结构图(横向循环, 纵向递归),然后根据题目分析递归结束条件和读入, 有时还需要进行剪枝。这里有一个我认为讲的比较好的视频(关于回溯的理论, 该up主还有一些关于题目的视频解答):带你学透回溯算法(理论篇)| 回溯法精讲!_哔哩哔哩_bilibili。