写在前面:本文题单均来自力扣的算法刷题计划,开这个系列主要是以题目与题解的形式对一些常见、常用算法进行归类和总结,希望在促进自己学习的同时也能帮助到看到这篇文章的大家。另外,本文并非一天一更~
目录
题目一:77. 组合
题目描述:
题目分析:
回溯法,先用for循环横向遍历每组数的头一位数,再用递归纵向遍历每组数头一位数后面跟的数,当path保存的数字够k了时就记录在res中,再删除path里的上一位数,以便存入后续的数。
题解代码:
class Solution {
public:
vector<vector<int>> result; //保存结果集合
vector<int> path; //记录每一次得出的单一结果
void backtracking(int n,int k,int startIndex)
{
if(path.size() == k) //若数字够k了就保存
{
result.push_back(path);
return;
}
for(int i=startIndex;i<=n-(k-path.size())+1;i++) //存在k==n的情况需要剪枝
{
path.push_back(i);
backtracking(n,k,i+1); //递归
path.pop_back(); //回溯
}
}
vector<vector<int>> combine(int n, int k) {
backtracking(n,k,1);
return result;
}
};
题目二:46. 全排列
题目描述:
题目分析:
仍是回溯法,与上一题类似,不过这题需要加入一个访问数组来避免重复的情况出现。
题解代码:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums,vector<bool> &visited){
if(path.size()==nums.size()) //长度够了就记录在result里
{
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(visited[i]) //若没访问过便继续下去
continue;
visited[i]=true;
path.push_back(nums[i]);
backtracking(nums,visited); // 这里是可以剪枝的,加一个index来记录遍历到哪个数了
path.pop_back();
visited[i]=false;
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> visited(nums.size(),false);
backtracking(nums,visited);
return result;
}
};
题目三:784. 字母大小写全排列
题目描述:
题目分析:
处理字符串的每一位即可,遇到数字加进path数组,遇到字母分两次情况(大小写)再加入path数组,当path长度等于s的长度时,就记录在res里,最后返回res即可。
另:这里对 s[index]^32 解释一下,由于a的ASCII码是97,A的ASCII码是65,差32,也就是说异或32后即可实现大小写字母的转换,或者写为 ^(1<<5)。
题解代码:
class Solution {
public:
vector<string> res;
vector<string> letterCasePermutation(string s) {
int size = s.size();
backtracking(s,"",0,size);
return res;
}
void backtracking(string s,string path,int index,int size)
{
if(index == size)
{
res.push_back(path);
return ;
}
if(s[index]>='0' && s[index]<='9') //遇到数字直接进入path
backtracking(s,path+s[index],index+1,size);
else
{
backtracking(s,path+s[index],index+1,size); //两次处理
backtracking(s,path+char(s[index]^32),index+1,size);
}
}
};