回溯法
回溯法又称为试探法,当探索到某一步时,发现原先选择达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。
分治算法:
将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同,求出子问题的解后合并就可以求出原问题。
一般步骤:
1.分解,将要解决的问题加分为若干规模较小的同类问题。
2.求解,当子问题划分得足够小时,用较简单的方法解决。
3.合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
打印ABC的全排列:
//打印a,b,c
#include <iostream>
#include <vector>
#include<string.h>
using namespace std;
void printabc(std::string abc,std::vector<std::string> &result,int n){
if(n==0){
result.push_back(abc);
return ;
}
if(strstr(abc.c_str(),"a")==0){
printabc(abc+'a',result, n-1);
}
if(strstr(abc.c_str(),"b")==0){
printabc(abc+'b',result, n-1);
}
if(strstr(abc.c_str(),"c")==0){
printabc(abc+'c',result, n-1);
}
}
int main ()
{
std::string tmp="";
std::vector<std::string> result;
printabc(tmp,result,3);
for(int i=0;i<result.size();i++){
//printf("%d",result.size());
std::string dd=result[i];
printf("%s\n",dd.c_str());
}
system("pause");
return 0;
}
题目:已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子集中的各个元素和为整数target的子集,结果中无重复的子集。
例如:nums[]=[10,1,2,7,6,1,5],target=8
结果为:[[1,7],[1,2,5],[2,6],[1,1,6]]
解题思路:回溯法再加截支;
#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
class Solution{
public:
std::vector<std::vector<int>> combinationsum2(std::vector<int>&candidates,int target){
std::vector<std::vector<int>>result;
std::vector<int> item;
std::set<std::vector<int>>res_set;
std::sort(candidates.begin(),candidates.end());
generate(0,candidates,result,item,res_set,0,target);
return result;
}
private:
void generate(int i,std::vector<int>&nums,std::vector<std::vector<int>>&result,
std::vector<int>&item,std::set<std::vector<int>>&res_set,int sum,int target){
if(sum>target||i>=nums.size()){
return ;
}
sum+=nums[i];
item.push_back(nums[i]);
if(sum==target&&res_set.find(item)==res_set.end()){
result.push_back(item);
res_set.insert(item);
}
generate(i+1,nums,result,item,res_set,sum,target);
sum=sum-nums[i];
item.pop_back();
generate(i+1,nums,result,item,res_set,sum,target);
}
};
int main(){
std::vector<int> nums;
nums.push_back(10);
nums.push_back(1);
nums.push_back(2);
nums.push_back(7);
nums.push_back(6);
nums.push_back(1);
nums.push_back(5);
std::vector<std::vector<int>>result;
Solution solve;
result =solve.combinationsum2(nums,8);
for(int i=0;i<result.size();i++){
if(result[i].size()==0){
printf("[]");
}
for(int j=0;j<result[i].size();j++){
printf("[%d]",result[i][j]);
}
printf("\n");
}
system("pause");
return 0;
}
生成括号(递归设计)
//n组括号,有多少种可能?
#include<iostream>
#include<vector>
using namespace std;
class Solution{
public:
std::vector<std::string>generationparenthesis(int n){
std::vector<std::string>result;
generate("",n,n,result);
return result;
}
private:
void generate(std::string item,int left,int right,std::vector<std::string>&result){
if(left==0&&right==0){
result.push_back(item);
return;
}
if(left>0){
generate(item+"(",left-1,right,result);
}
if(left<right){
generate(item+")",left,right-1,result);
}
}
};
int main(){
Solution solve;
std::vector<std::string>result=solve.generationparenthesis(3);
for(int i=0;i<result.size();i++){
printf("%s\n",result[i].c_str());
}
system("pause");
return 0;
}
N皇后(回溯法)
#include<iostream>
#include<vector>
using namespace std;
//****N皇后问题:将N个皇后放摆再N*N的棋盘中,相互不可攻击,有多少种摆法方法,具体每种摆放方法时什么样子的?****/
// 解决办法:利用递归对棋盘的每一行放置皇后,放置时,按列排序寻找可以放置皇后的列,若可以放置皇后,将皇后放置该位置,
// 并更新mask标记数组,递归进行一行的皇后放置;当该次递归结束后,恢复mask数组,并尝试下一个可能放皇后的列。
void put_down_the_queen(int x,int y,std::vector<std::vector<int>> &mark){ //放置皇后,把标记至为1
static const int EX[]={-1,1, 0, 0,-1,-1, 1,1}; //static的目的说只要一份EX,EY
static const int EY[]={ 0,0,-1, 1,-1, 1,-1,1}; //方向数组
mark[x][y]=1; //(x,y)放置皇后进行标记
for(int i=1;i<mark.size();i++){ //8个方向,每个方向向外延伸1至N-1
for(int j=0;j<8;j++){
int new_x=x+i*EX[j]; //新的位置向8个方向延伸,每个方向最多延伸N-1
int new_y=y+i*EY[j];
if( new_x>=0&&new_x<mark.size()&&new_y>=0&&new_y<mark.size()) //检查新位置是否还在棋盘内
mark[new_x][new_y]=1;
}
}
}
void generate(int k,int n, //k代表完成了几个皇后的放置(正在放置第k行皇后)
std::vector<std::string> &location, //某次结果存储在location中
std::vector<std::vector<std::string>> &result, //最终结果存储在result
std::vector<std::vector<int>> &mark){ //表示棋盘的标记数组
if(k==n){ //当k==n时,代表完成了第0至第n-1行皇后的放置,所有皇后完成放置后,将记录皇后位置的
result.push_back(location); //location数组push进入result
return;
}
for(int i=0;i<n;i++){ //按顺序尝试第0至n-1列
if(mark[k][i]==0){ //如果当前满足mark[k][i]==0条件,即可以放置皇后
std::vector<std::vector<int>>tmp_mark=mark;//记录回溯前的mark镜像
location[k][i]='Q'; //记录当前皇后的位置
put_down_the_queen(k,i,mark); //放置皇后
generate(k+1,n,location,result,mark); //递归下一行皇后放置
mark=tmp_mark; //将mark重新赋值为回溯前状态
location[k][i]='.'; //将当前尝试的皇后位置重新置.
}
}
}
class Solution{
public:
std::vector<std::vector<std::string>>solveNQueens(int n){
std::vector<std::vector<std::string>>result; //存储最终结果的数组
std::vector<std::vector<int>> mark; //标记棋盘是否可以放置皇后的二维数组
std::vector<std::string> location;//存储某个摆放结果,当完成一次递归找到结果后,将location push进入result
for(int i=0;i<n;i++){
mark.push_back(std::vector<int>());
for(int j=0;j<n;j++){
mark[i].push_back(0);
}
location.push_back("");
location[i].append(n,'.');
}
generate(0,n,location,result,mark);
return result;
}
};
int main(){
std::vector<std::vector<std::string>>result;
Solution solve;
result=solve.solveNQueens(8);
for(int i=0;i<result.size();i++){
printf("i=%d\n",i);
for(int j=0;j<result[i].size();j++){
printf("%s\n",result[i][j].c_str());
}
printf("\n");
}
system("pause");
return 0;
}
手机键盘输入字母的组合:
递归四要素:入参,出口,如何递归,第一条数据执行后怎么初始化第二条递归数据
//手机号码显示
#include<iostream>
#include<vector>
#include<string>
using namespace std;
void KeyboardShow(string aa,string keep,vector<string> ss,int number){
if(number == aa.size()){
cout<<keep<<" ";
return ;
}
int index =aa[number] - '0';
for(int i = 0;i <ss[index].size();i++)
{
keep.push_back(ss[index][i]);
KeyboardShow(aa,keep,ss,number+1);
keep.pop_back();
}
return;
}
int main()
{
vector<string> ss;
ss.push_back("abc");
ss.push_back("def");
ss.push_back("ghi");
ss.push_back("jkl");
ss.push_back("mno");
ss.push_back("pqrs");
ss.push_back("tuv");
ss.push_back("wxyz");
string temp ="";
string kkk;
cin>>kkk;
KeyboardShow(kkk,temp,ss,0);
system("pause");
return 0;
}