day30 2023/03/02
那几道难题可能等到周末再来做,最近时间太太太太紧张了
回溯算法
回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。
回溯法就是暴力搜索,并不是什么高效的算法,最多再剪枝一下。
77.组合
抽象为如下树形结构:
class Solution {
public:
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();
}
}
vector<vector<int>> combine(int n, int k) {
backtracking(n,k,1);
return result;
}
};
216.组合总和Ⅲ
抽象为如下树形结构:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(int n,int k,int sum,int startIndex)
{
if(path.size()==k)
{
if(sum==n)
result.push_back(path);
return;
}
for(int i=startIndex;i<=9;i++)
{
sum+=i;
path.push_back(i);
backtracking(n,k,sum,i+1);
sum-=i;
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(n,k,0,1);
return result;
}
};
17.电话号码的字母组合
抽象为以下树形结构
代码如下:
class Solution {
public:
string lettermap[10]={
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz",
};
vector<string> result;
string path;
void backtracking(string digits,int index)
{
if(index==digits.size())
{
result.push_back(path);
return;
}
int digit=digits[index]-'0';
string letter=lettermap[digit];
for(int i=0;i<letter.size();i++)
{
path.push_back(letter[i]);
backtracking(digits,index+1);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
if(digits.size()==0)
return result;
backtracking(digits,0);
return result;
}
};
39.组合总和
抽象成树形结构如下:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates,int target,int sum,int startIndex)
{
if(sum>target) return;
if(sum==target)
{
result.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size();i++)
{
sum+=candidates[i];
path.push_back(candidates[i]);
backtracking(candidates,target,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates,target,0,0);
return result;
}
};
40.组合总和Ⅱ
树形结构如图所示:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates,int target,int sum,int startIndex,vector<bool>& used)
{
if(sum>target) return;
if(sum==target)
{
result.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size();i++)
{
if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false)
continue;
used[i]=true;
sum+=candidates[i];
path.push_back(candidates[i]);
backtracking(candidates,target,sum,i+1,used);
used[i]=false;
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<bool> used(candidates.size(),false);
sort(candidates.begin(),candidates.end());
backtracking(candidates,target,0,0,used);
return result;
}
};
131.分割回文串
抽象为如下树形结构
代码如下:
class Solution {
public:
vector<vector<string>> result;
vector<string> path;
bool isHuiwen(string& s,int start,int end)
{
for(int i=start,j=end;i<j;i++,j--)
{
if(s[i]!=s[j])
return false;
}
return true;
}
void backtracking(string& s,int startIndex)
{
if(startIndex>=s.size())
{
result.push_back(path);
return;
}
for(int i=startIndex;i<s.size();i++)
{
if(isHuiwen(s,startIndex,i)==true)
{
string s1=s.substr(startIndex,i-startIndex+1);
path.push_back(s1);
}
else
{
continue;
}
backtracking(s,i+1);
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
backtracking(s,0);
return result;
}
};
93.复原IP地址
抽象为树形结构
抽象为树型结构,如图:
代码如下:
class Solution {
public:
vector<string> result;
string s;
bool isValidNet(string& str,int start,int end)
{
if(start>end) return false;
if(str[start]=='0'&&start!=end)//0开头的不合法
{
return false;
}
int num=0;
for(int i=start;i<=end;i++)
{
//遇到非数字字符直接返回错误
if(str[i]<'0'||str[i]>'9')
return false;
//大于255也返回错误
num=num*10+(str[i]-'0');
if(num>255)
return false;
}
return true;
}
void backtracking(string& s,int startIndex,int pointNum)//pointNum代表句点个数
{
if(pointNum==3)
{
if(isValidNet(s,startIndex,s.size()-1)==true)
{
result.push_back(s);
return;
}
}
for(int i=startIndex;i<s.size();i++)
{
if(isValidNet(s,startIndex,i)==true)
{
s.insert(s.begin()+i+1,'.');
pointNum++;
backtracking(s,i+2,pointNum);//注意这里是从i+2开始呢
s.erase(s.begin()+i+1);
pointNum--;
}
else break;
}
}
vector<string> restoreIpAddresses(string s) {
backtracking(s,0,0);
return result;
}
};
78.子集
抽象为树形结构:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int> & nums,int startIndex)
{
result.push_back(path);
if(startIndex>=nums.size())
{
return ;
}
for(int i=startIndex;i<nums.size();i++)
{
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backtracking(nums,0);
return result;
}
};
90.子集Ⅱ
抽象为树形结构:
如图所示: (注意去重需要先对集合排序)
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums,int startIndex,vector<bool>& used)
{
result.push_back(path);
if(startIndex>=nums.size())
return;
for(int i=startIndex;i<nums.size();i++)
{
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false)
continue;
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,i+1,used);
used[i]=false;
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<bool> used(nums.size(),false);
sort(nums.begin(),nums.end());
//记得要排序
backtracking(nums,0,used);
return result;
}
};
491.递增子序列
抽象为树形结构:
抽象为树形结构如图:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums,int startIndex)
{
if(path.size()>1)
{
result.push_back(path);
// return;不能加return,因为要取树上的节点
}
unordered_set<int> uset;//对本层元素进行去重
for(int i=startIndex;i<nums.size();i++)
{
if((!path.empty()&&nums[i]<path.back())||(uset.find(nums[i])!=uset.end()))
{
continue;
}
uset.insert(nums[i]);
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
backtracking(nums,0);
return result;
}
};
46.全排列
抽象为树形结构:
抽象成树形结构如下:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums,vector<bool>& used)
{
if(path.size()==nums.size())
{
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(used[i]==true) continue;
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,used);
used[i]=false;
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> used(nums.size(),false);
backtracking(nums,used);
return result;
}
};
47.全排列Ⅱ
抽象为树形结构:
抽象为一棵树,去重过程如图:
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums,vector<bool>& used)
{
if(path.size()==nums.size())
{
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false)
{
continue;
}
if(used[i]==false)
{
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,used);
used[i]=false;
path.pop_back();
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<bool> used(nums.size(),false);
backtracking(nums,used);
return result;
}
};