回溯(Flash back)学习

Posted 楠c

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回溯(Flash back)学习相关的知识,希望对你有一定的参考价值。

目录

回溯是一种通过穷举所有可能情况来找到所有解的思想。如果一个候选解最后被发现并不是可行解,回溯思想会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。回溯一般会结合在搜索算法中

普通回溯

矩阵中的路径

class Solution 
private:
       int m;
       int n;
    bool DFS(vector<vector<char>>& board, string& word,int x,int y,int k)
    
        if(x<0||y<0||x>=m||y>=n||board[x][y]!=word[k])
           return false;
        if(k==word.size()-1)//一直为ture,才能进来,说明都能搜索到,等于字符串长度就退出
           return true;
        //先标记为' '防止影响这个点的上下左右搜索(当前方案不要走回头路)
        board[x][y]=' ';   
        bool ret=DFS(board,word,x+1,y,k+1)||DFS(board,word,x-1,y,k+1)||DFS(board,word,x,y+1,k+1)||DFS(board,word,x,y-1,k+1);
        //恢复,防止影响别人搜索(进行下一次搜索方案)
        board[x][y]=word[k];
        return ret;
    
public:
    bool exist(vector<vector<char>>& board, string word) 
         m=board.size();
         n=board[0].size();

         for(int i=0;i<m;i++)
         
             for(int j=0;j<n;j++)
             
                 //如果某一点搜索到全部单词就返回
                 if(DFS(board,word,i,j,0))
                 return true;
             
         
         return false;
    
;

二叉树和为某一值的路径

深度搜索+回溯。创建一个临时数组,先push进节点,然后搜索左和右,不满足的话回溯。


class Solution 
private:
    vector<int> temp;
    void Dfs(TreeNode* root, int target,vector<vector<int>>& ret)
    
        if(root==nullptr)
          return;
        //先插入临时数组
        temp.push_back(root->val);
        target-=root->val;
        //左右都为空,且目标值为0才插入到二维数组当中
        if(root->left==nullptr&&root->right==nullptr&&target==0)
        
            ret.push_back(temp);
        
        //搜索左
        Dfs(root->left,target,ret);
        //搜索右
        Dfs(root->right,target,ret);
        //回溯
        temp.pop_back();
    

public:
    vector<vector<int>> pathSum(TreeNode* root, int target) 
           
           vector<vector<int>> ret;
           Dfs(root,target,ret);
           return ret;
    
;

N皇后


class Solution 
    void DFS(vector<vector<pair<int,int>>>& ret,vector<pair<int,int>>& temp,int curRow,int n)
    
        if(curRow==n)
        
            //临时数组坐标全部符合,curRow才能加到n,才能入结果数组
            ret.push_back(temp);
        

        for(int col=0;col<n;col++)
        
            //坐标有效才插入临时数组
            //临时数组:(保护当前一种方法的所有皇后坐标)
            if(isValid(temp,curRow,col))
            
            temp.push_back(make_pair(curRow,col));
            DFS(ret,temp,curRow+1,n);
            temp.pop_back();
            
        
    
    //皇后坐标是否有效
    bool isValid(vector<pair<int,int>>& temp,int curRow,int col)
    
        for(auto& e:temp)
        
            if(e.second==col||e.first+e.second==curRow+col||e.first-e.second==curRow-col)
               return false;
        
        return true;
    
    //输出有点奇怪,所以要转换
    vector<vector<string>> transRet(vector<vector<pair<int,int>>> ret,int n)
    
        vector<vector<string>> vv;
        for(auto& v:ret)
        
           //观察输出,二维数组,每个一维数组由4个string组成,每个string都有四个'.'
           vector<string> vs(n,string(n,'.'));
           for(auto& e:v)
           
               vs[e.first][e.second]='Q';
           
           vv.push_back(vs);
        
        return vv;
    
public:
    vector<vector<string>> solveNQueens(int n) 
     vector<vector<pair<int,int>>> ret;
     vector<pair<int,int>> temp;
     DFS(ret,temp,0,n);

     vector<vector<string>> vv=transRet(ret,n);

     return vv;
    
;

N皇后||

我们用一维临时数组来存储当前方法的皇后坐标。有几种方法就插入几次二维数组。最后二维数组的size就是方法数量

class Solution 
private:
    void DFS(vector<vector<pair<int,int>>>& ret,vector<pair<int,int>>& temp,int curRow,int n)
    
        if(curRow==n)
        
            ret.push_back(temp);
            return;
        
        for(int col=0;col<n;col++)
        
            if(isVaild(temp,curRow,col))
            
                temp.push_back(make_pair(curRow,col));
                DFS(ret,temp,curRow+1,n);
                temp.pop_back();
            
        
    
    bool isVaild(vector<pair<int,int>> temp,int curRow,int col)
    
               for(auto&e :temp)
               
                   if(col==e.second||curRow+col==e.first+e.second||curRow-col==e.first-e.second)
                     return false;
               
               return true;        
    
public:
    int totalNQueens(int n) 
           vector<vector<pair<int,int>>> ret;
           vector<pair<int,int>> temp;

           DFS(ret,temp,0,n);

           return ret.size();
    
;

排列问题

全排列

字符串排列

字符串排列


题目的样例要求向前回退,即b可以匹配a,所以在循环中我们每次都要从0开始,但是这样肯定会有aaa,aab,aac,等这种一个元素重复使用的情况。


vis是一个标记数组


这样就避免了重复使用一个元素。

class Solution 
private:
    void DFS(string s,unordered_set<string>& ret,vector<bool>& vis,string curStr,int index)
    
        //放入哈希set当中,这样做的原因是防止字符串中有重复的例如"aab"

        if(index==s.size())
        
            ret.insert(curStr);
            return;
        
        for(int i=0;i<s.size();i++)
        
            if(vis[i])
            
            vis[i]=false;
            DFS(s,ret,vis,curStr+s[i],index+1);
            vis[i]=true;
            
        
    
public:
    vector<string> permutation(string s) 
      
      unordered_set<string> ret;
      vector<bool> vis(s.size(),true);
      DFS(s,ret,vis,"",0);
      
      //去重之后再放进数组中返回
      vector<string> ret1(ret.begin(),ret.end());
      return ret1;

    
;

24点游戏

#include<iostream>
#include<string>
#include<vector>
using namespace std;


bool Dfs(vector<double>& v,vector<bool> used,int point,double result,int index)

    if(index==4&&result==point)
    
        return true;
    
    for(int i=0;i<4;i++)
    
       if(!used[i])
       
       used[i]=true;
       bool ret=Dfs(v,used,point,result+v[i],index+1)\\
           ||Dfs(v,used,point,result-v[i],index+1)\\
           ||Dfs(v,used,point,result*v[i],index+1)\\
           ||Dfs(v,used,point,result/v[i],index+1);
       used[i]=false;
       if(ret)
       
          return true;
       
       

    
    
    return false;

int main()

    vector<double> v(4,0);
    vector<bool> used(4,false);
    while(cin>>v[0]>>v[1]>>v[2]>>v[3])
    
        
        if(Dfs(v,used,24,0,0))
        
          cout<<"true"<<endl;
        
        else
        
            cout<<"false"<<endl;
        
    
    
    return 0;

活字印刷

可以向前回退,但重复元素不能使用。即循环从0开始,且需要标记数组

class Solution 
private:
    void DFS(string tiles,unordered_set<string>& ret,vector<bool>& vis,string curStr)
    
        
        if(curStr!="")
        
        ret.insert(curStr);
        

        for(int i=0;i<tiles.size();i++)
        
            if(vis[i])
            
                vis[i]=false;
                DFS(tiles,ret,vis,curStr+tiles[i]);
                vis[i]=true;
            
        


    

public:
    int numTilePossibilities(string tiles) 
         unordered_set<string> ret;
         vector<bool> vis(tiles.size(),true);

         DFS(tiles,ret,vis,"");
         
         return ret.size();
    
;

组合问题

电话号码组合

Map建立号码与字符串映射。
在代码中,DFS里,curStr+e即一个回溯的过程。例如当前是cur是空串,e依次被映射为abc,先从a开始,继续调用DFS,由于index++,所以e依次被映射到def,所以curStr现在是a,就开始和def两两组合,符合条件入结果数组。执行完后回溯,curStr成为b,又开始新的一轮。

class Solution 
private:
    unordered_map<char,string> Map;
    void DFS(const string& digits,vector<string>& Allret,string curStr,int idx)
    
        if(idx==digits.size())
        //只有和字符串大小相等时才加入数组当中,然后结束当前深搜
           Allret.push_back(curStr);
           return;
        
        //取出当前字符对应的字符串
        string curMap=Map[digits[idx]];
        for(char e:curMap)
        
            //curStr+e,即为一个回溯的过程
            //从DFS返回他就又成为了curStr
            //curStr+e是个临时变量,所以形参不能是引用
            DFS(digits,Allret,curStr+e,idx+1);
        
    
public:
    vector<string> letterCombinations(string digits) 
         vector<string> Allret;
         if(digits.size()==0)
          return Allret;
         Map=哪个 Javascript 历史回溯实现是最好的?

简单文件上传

Angular:位置回溯历史

Gremlin 图遍历回溯

从当前日期回溯 24 个月的 where 子句存在问题

MATLAB datenum日期转换为Python日期