回溯算法练习题

回溯是一个常见的算法,类似于深搜/广搜,会穷举每一个可能。但是会有一个恢复选择的操作。

算法核心框架如下:

for 选择  in  选择列表:
	#做选择
	将该选择从选择列表里移除
	路径.add(选择)
	backtrace(路径,选择列表)
	
	#撤销选择
	路径.remove(选择)
	将该选项恢复到选择列表

经典例题

1.电话号码的字母组合
在这里插入图片描述

class Solution {
public:
    void backtrack(string& digits,vector<string>& ret ,string curstr,int  curdeepth){
        //边界判断
        if(curdeepth==digits.size()){
            if(!curstr.empty())
                ret.push_back(curstr);
            return;
        }

        //选择路径
        for(int i=0;i<mapString[digits[curdeepth]-'0'].size();++i){
            
            curstr += mapString[digits[curdeepth]-'0'][i];

            backtrack(digits,ret,curstr,curdeepth+1);
            curstr.pop_back();//尾删,撤销选择,向上回溯

        }

    }

    vector<string> letterCombinations(string digits) {
        vector<string>  ret;

        backtrack(digits,ret,"",0);
        return  ret;
    }
private:
    vector<string> mapString = {"", "", "abc", "def", "ghi", "jkl", "mno","pqrs", "tuv", "wxyz"};
};

2.组合总和
在这里插入图片描述

DFS+回溯可解。
类似于上一题,这里我用了一个deepth变量来控制决策树的层数。

class Solution {
public:
    void backtrace(vector<int>& candidates,vector<vector<int>>&ret, vector<int>&tmp,int sum,int target,int deepth){
        //边界判断
        if(sum>target) return;
        if(sum==target){        
            ret.push_back(tmp);
            return;
        }

        //搜索
        for(int i=deepth;i<candidates.size();++i){
            tmp.push_back(candidates[i]); //选择
            //进入下一层决策树
            backtrace(candidates,ret,tmp,sum+candidates[i],target,deepth++);   
            //取消本次选择        
            tmp.pop_back();
        }
    }


    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ret;
        vector<int> tmp; //记录路径
        int sum=0;
        int deepth=0;
        backtrace(candidates,ret,tmp,sum,target,deepth);
        return  ret;
    }

};

3.活字印刷

在这里插入图片描述

class Solution {
public:

    void  backtrace(string& tiles,unordered_set<string>& dict,string & curstr,vector<int>& usedid){
        if(dict.count(curstr)==0 && curstr.size()!=0){
            dict.insert(curstr);
        }

        for(int i=0;i<tiles.size();++i){
            //已使用过的字符则跳过
            if(usedid[i]==1) 
                continue;
            usedid[i]=1;
			//遍历下一层
            string tmp=curstr + tiles[i];
            backtrace(tiles,dict,tmp,usedid);
			//回溯
            tmp.pop_back();
            usedid[i]=0;
        }

    }

    int numTilePossibilities(string tiles) {
        unordered_set<string> dict;   //方便查重
        vector<int> usedid(tiles.size(),0); //记录被访问过的字符
        string curstr;
        backtrace(tiles,dict,curstr,usedid);
        return  dict.size();
    }

};

3.N 皇后
在这里插入图片描述

4.N皇后 II
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值