搜索——回溯算法

回溯算法是一种基于深度优先搜索的求解排列组合问题的方法,它不同于普通DFS,更注重解决路径选择的问题。在求解过程中,需要对元素进行标记以避免重复访问。文中列举了15个使用回溯算法解决的问题,包括电话号码的字母组合、复原IP地址、单词搜索等,展示了回溯算法在解决这类问题上的广泛适用性。
摘要由CSDN通过智能技术生成

Backtracking(回溯)属于 DFS。

普通 DFS 主要用在 可达性问题 ,这种问题只需要执行到特点的位置然后返回即可。

而 Backtracking 主要用于求解 排列组合 问题,例如有 { ‘a’,‘b’,‘c’ } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回之后还会继续执行求解过程

因为 Backtracking 不是立即返回,而要继续求解,因此在程序实现时,需要注意对元素的标记问题

在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;

但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。

1、电话号码的字母组合

class Solution {
   
public:
    vector<string> table = {
   "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    vector<string> res;
    string str;
    vector<string> letterCombinations(string digits) {
   
        if(digits.size()==0)    return res;
        dfs(digits,0);
        return res;
    }

    void dfs(string digits,int index){
   
        if(index==digits.size()){
   
            res.push_back(str);
            return;
        }
        string s = table[digits[index] - '2'];
        for(int i=0;i<s.size();i++){
   
            str.push_back(s[i]);
            dfs(digits,index+1);
            str.pop_back();
        }
        return;
    }
};

2、复原IP地址

class Solution {
   
public:
    bool isValid(string ip)
{
   
    int val = stoi(ip);
    if (val > 255)    return false;
    if (ip.size() >= 2 && ip[0] == '0')    return false;
    return true;
}
void dfs(string& s, int pos, vector<string> &path, vector<string>& res)
{
   
    //首先判断剩余的位数,是不是还能满足要求,比如25525511135,若2.5.5.25511135显然不满足,这可以预判
    //4组,每组最多3位数字
    int maxLen = (4 - path.size()) * 3;
    if (s.size() - pos > maxLen)    return;
    if (path.size() == 4 && pos == s.size()) {
   
        string ans = "";
        for (int i = 0; i < 4; ++i) {
   
            ans += path[i];
            if (i != 3)    ans += ".";
        }
        res.push_back(ans);
        return;
    }
    //回溯算法的典型模式,循环递归
    for (int i = pos; i < s.size() && i <= pos + 2; ++i) {
   
        string ip = s.substr(pos, i - pos+1);
        if (!isValid(ip))    continue;
        path.push_back(ip);
        dfs(s, i + 1, path, res);
        path.pop_back();
    }
}
vector<string> restoreIpAddresses(string s) 
{
   
    //找3个.的位置,每个.之前组成的的数值必须要小于255,且以0开头的除非数字是0本身,否则也是非法
    vector<string> res;
    if (s.size() == 0 || s.size() < 4)    return res;
    vector<string> path;//存储从根开始的到叶子节点的满足条件的路径,因为最多3位数字一组,所以同一层横向循环时尝试最多3个位的长度
    dfs(s, 0, path, res);
    return res;
}
};

3、单词搜索

class Solution {
   
public:
    bool exist(vector<vector<char>>& board, string word) {
   
        m=board.size();
        n=board[0].size();
        if(m==0 || n==0)    return false;
        vector<vector<bool>> visit(m,vector<bool>(n,false));
        
        for(int i=0;i<m;i++){
   
            for(int j=0;j<n;j++){
   
                if(board[i][j]==word[0]){
   
                    if(dfs(board,visit,word,0,i,j))
                        return true;
                }
            }
        }

        return false;
    }

private:
    int m,n;
    int dit[4][2] = {
   1,0,-1,0,0,1,0,-1};
    bool dfs(vector<vector<char>>& board, vector<vector<bool>>& visit,string& word,int index,int i,int j){
   
        if(i<0 || j<0 || i>=m || j>=n 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值