LeetCode77. 组合
LeetCode46. 全排列
LeetCode784. 字母大小写全排列
题目链接直接给大家挂上
回溯:简单的就可以理解为递归的“修改版”,举个例子:如平常的二叉树的遍历,我们在使用dfs时,选择递归边界指针为空。然后执行每个遍历节点的操作(如输出)。执行完成之后我们就没有别的操作了。而回溯便可以在每一步递归完成的时候,回头看看(做一些操作:还原)
回溯和递归的算法设计相同:1.递归边界;2.参数传递;3.每层递归的操作
LeetCode77. 组合
这个题目作为回溯的入门:[1-n],K位数组合,不重复使用,再根据组合的定义,不能有交换位置的结果重复出现(如[2,1] = [1,2])
递归边界:满足k个数
参数传递:向下层递归传递时,排除当前位置 +1
每层操作:把这位数加入到暂存结果,递归传递,这个数已经用过,从暂存结果中删除(回溯)
class Solution {
private:
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = startIndex; i <= n; i++) {
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return result;
}
};
LeetCode46. 全排列
个人感觉全排列还是比较好写的,直接DFS,注意与组合题区分,元素不能重复使用,但是位置不同就是一个符合条件的情况(如[1,2,3] 和 [1,3,2])是两种不同的结果
递归边界:满足全部数都已经使用
参数传递:向下层递归传递时,排除当前位置 +1
每层操作:用到了访问标志,数组中这个下标的元素没有访问过,才执行这个下标的操作。把这位数加入到暂存结果,递归传递,这个数已经用过,从暂存结果中删除(回溯),不同的是每层我们都要从数组下标0开始,来处理以上的情况(如[1,2,3] 和 [1,3,2])
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<bool> st;//标志位
vector<vector<int>> permute(vector<int>& nums) {
int n=nums.size();
for(int i = 0; i < nums.size(); i++)st.push_back(false);//初始时nums[]的每个数字都没别选过,都是false
dfs(0, nums);
return ans;
}
void dfs(int idx,vector<int>& nums)//u表示选到了path[]的第几个位置了
{
if(idx == nums.size())//选完了,将path[]存入ans中
{
ans.push_back(path);
return;
}
for(int i = 0; i < nums.size(); i++)
{
if(!st[i])//如果nums[i]未被选择过
{
st[i] = true;
path.push_back(nums[i]);//将nums[i]放入path中
dfs(idx + 1,nums);//进行下一层的搜索
st[i] = false;//现场的还原
path.pop_back();//现场的还原
}
}
}
};
LeetCode784. 字母大小写全排列
这个题目和第一个组合题基本是一样的。无非是回溯的操作,以及处理的数据不同
递归边界:访问的下标已经处理完字符串最后一个元素
参数传递:向下层递归传递时,排除当前位置 +1
每层操作:根据题意是大写字母变小写字母,小写字母变大写字母。从当前下标开始,遇到字母执行变型操作,压入结果。进入下一层递归,下层递归结束,把当前字母变型回原来的(回溯)。
class Solution {
public:
void dfs(string &s, int len, int idx, vector<string> &ans)
{
if(idx == len)
return;
for(int i = idx; i < len; i++)
{
if(s[i] >= 'a' && s[i] <= 'z')
{
s[i] = s[i] - 32;//变大写
ans.push_back(s);
dfs(s, len, i + 1, ans);
s[i] = s[i] + 32;//回溯
}
if(s[i] >= 'A' && s[i] <= 'Z')
{
s[i] = s[i] + 32;
ans.push_back(s);
dfs(s, len, i + 1, ans);
s[i] = s[i] - 32;//回溯
}
}
}
vector<string> letterCasePermutation(string s) {
int len = s.length();
vector<string> ans;
ans.push_back(s);
dfs(s, len, 0, ans);
return ans;
}
};