Leetcode之递归、回溯与分治

回溯法
回溯法又称为试探法,当探索到某一步时,发现原先选择达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。

分治算法:
将一个规模为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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值