递归搜索与回溯专题篇二

目录

N皇后

有效的数独

解数独

单词搜索

黄金矿工

不同路径III


N皇后

题目

思路

根据题意可知,要想得到n皇后的摆放方案,结果须满足每一行及每一列都只有一个皇后,且每个主对角线和副对角线上只能有一个皇后,我们的做法是,使用三个数组记录每一列,每一个主对角线以及每一个副对角线上是否有皇后,事先创建一个和原二维矩阵同规模大小的二维矩阵,每个位置都设置为'.',然后根据n皇后的规则,每一行每个位置的填放皇后的位置,填皇后时,先判断这一列,当前位置的主对角线和副对角线上是否有皇后,如果都没有的话,再填皇后,递归的出口是已经填放完最后一行皇后的位置。

代码

class Solution {
    bool checkCol[10],checkDig1[20],checkDig2[20];
    vector<vector<string>> ret;
    vector<string> path;

public:
    vector<vector<string>> solveNQueens(int n) {
        path.resize(n);
        for(int i=0;i<n;i++)
            path[i].append(n,'.');
        dfs(n,0);
        return ret;
    }

    void dfs(int n,int row){
        if(row==n){
            ret.push_back(path);
            return;
        }
        for(int col=0;col<n;col++){
            if(!checkCol[col] && !checkDig1[row-col+n] && !checkDig2[row+col]){
                path[row][col]='Q';
                checkCol[col]=checkDig1[row-col+n]=checkDig2[row+col]=true;
                dfs(n,row+1);
                checkCol[col]=checkDig1[row-col+n]=checkDig2[row+col]=false;
                path[row][col]='.';
            }
        }
    }
};
有效的数独

题目

思路

解决这道题并不会利用到递归和回溯,之所以放这道题是为了解决下一道题准备的,因为题目要求每一行每一列1~9每个数字只能出现一次,且1~9在每个3x3的宫格内只能出现一次。

那么该如何处理上面这3条规则那?使用一个数组row来记录每一行每个数字是否出现,使用一个数组col来记录每一列每个数字是否出现,使用一个数组grid来记录每个3x3的宫格内每个数字是否出现过,如果不满足上面的三个条件,说明不是数独;否则是数独。

代码

class Solution {
    bool row[9][10];
    bool col[9][10];
    bool grid[3][3][10];
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                if(board[i][j]!='.'){
                    int num=board[i][j]-'0';
                    if(row[i][num] || col[j][num] || grid[i/3][j/3][num])
                        return false;
                    row[i][num]=col[j][num]=grid[i/3][j/3][num]=true;
                }
            }
        return true;
    }
};
解数独

题目

思路

如何理解数独,在上一道题已经理解过了,题目中值填写了部分位置的值,要求我们填写剩下的位置,使之满足数独,数独的条件是每一行每一列1~9每个数字只能出现一次,且1~9在每个3x3的宫格内只能出现一次。

那么该如何处理上面这3条规则那?和上一道题一样,使用一个数组row来记录每一行每个数字是否出现,使用一个数组col来记录每一列每个数字是否出现,使用一个数组grid来记录每个3x3的宫格内每个数字是否出现过,如果不满足上面的三个条件,说明不是数独;否则是数独。

填写每个空位置时先判断1~9的某个值是否已经在每一行每一列以及每一个3x3的宫格内出现过,如果没有出现过才填写,并递归填写剩下的位置。

代码

class Solution {
    bool row[9][10];
    bool col[9][10];
    bool grid[3][3][10];
public:
    void solveSudoku(vector<vector<char>>& board) {
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                if(board[i][j]!='.'){
                    int num=board[i][j]-'0';
                    row[i][num]=col[j][num]=grid[i/3][j/3][num]=true;
                }
            }
        dfs(board);
    }

    bool dfs(vector<vector<char>>& board){
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                if(board[i][j]=='.'){
                    //填数
                    for(int num=1;num<=9;num++){
                        if(!row[i][num] && !col[j][num] && !grid[i/3][j/3][num]){
                            board[i][j]=num+'0';
                            row[i][num]=col[j][num]=grid[i/3][j/3][num]=true;
                            if(dfs(board)) return true;
                            row[i][num]=col[j][num]=grid[i/3][j/3][num]=false;
                            board[i][j]='.';
                        }
                    }
                    return false;
                }
            }
        return true;
    }
};
单词搜索

题目

思路

解决这道题是使用DFS,先扫描原始二维矩阵中的每个位置,判断是否与字符串第一个位置的值相等,如果相等,则对该位置进行DFS,递归的出口是匹配完字符串的所有位置的字符。

代码

class Solution {
    int m,n;
    bool vis[6][6];
public:
    bool exist(vector<vector<char>>& grid, string word) {
        m=grid.size(),n=grid[0].size();
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
            {
                if(grid[i][j]==word[0])
                {
                    //  memset(vis, false, sizeof(vis)); // 重置 vis 数组
                    vis[i][j]=true;
                    if(dfs(grid,i,j,word,1)) return true;
                    vis[i][j]=false;
                }
            }
        return false;
    }

    int dx[4]={1,-1,0,0};
    int dy[4]={0,0,1,-1};

    bool dfs(vector<vector<char>>& grid,int i,int j,string word,int pos){
        if(pos==word.size()) return true;
        for(int k=0;k<4;k++)
        {
            int x=i+dx[k];
            int y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && grid[x][y]==word[pos]){
                vis[x][y]=true;
                if(dfs(grid,x,y,word,pos+1)) return true;
                vis[x][y]=false;
            }
        }
        return false;
    }
};
黄金矿工

题目

思路

解决这道题也是使用DFS来解决,扫描整个二维数组,判断每个位置的值是否不为0,如果不为0,则对该位置进行DFS,因为不能走已经走过的位置,因此需要使用一个二维矩阵来标记已经访问过的位置,没有递归出口,递归结束就是处理到不再能继续递归。

代码

class Solution {
    bool vis[16][16];
    int ret,m,n;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
public:
    int getMaximumGold(vector<vector<int>>& grid) {
        m=grid.size(),n=grid[0].size();
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(grid[i][j]){
                    vis[i][j]=true;
                    dfs(grid,i,j,grid[i][j]);
                    vis[i][j]=false;
                }
            }
        return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j,int sum){
        ret=max(ret,sum);
        for(int k=0;k<4;k++){
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && grid[x][y]){
                vis[x][y]=true;
                dfs(grid,x,y,sum+grid[x][y]);
                vis[x][y]=false;
            }
        }
    }
};
不同路径III

题目

思路

之前讲解过不同路径和不同路径II,都是使用动态规划来解决的,这道题之所以没有使用动态规划来解决是因为使用动态规划来解决这道题比较困难,下面将使用DFS来解决这道题。

首先扫描整个二维矩阵,计算出0的个数以及起始位置的坐标,然后从起始位置进行DFS,每走一步对步数进行++,直到步数等于原始二维矩阵0的个数+2(起始位置和结束位置),因为不能走已经走过的位置,因此需要使用一个二维矩阵来标记已经走过的位置。

代码

class Solution {
    bool vis[21][21];
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int m,n,ret,sum;
public:
    int uniquePathsIII(vector<vector<int>>& grid) {
        m=grid.size(),n=grid[0].size();
        int bx,by;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(grid[i][j]==1)
                    bx=i,by=j;
                else if(grid[i][j]==0)
                    sum++;
        sum+=2;
        vis[bx][by]=true;
        dfs(grid,bx,by,1);
        return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j,int val){
        if(grid[i][j]==2){
            if(val==sum)
                ret++;
            return;
        }
        for(int k=0;k<4;k++){
            int x=i+dx[k],y=j+dy[k];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && grid[x][y]!=-1){
                vis[x][y]=true;
                dfs(grid,x,y,val+1);
                vis[x][y]=false;
            }
        }
    }
};

评论 193
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新绿MEHO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值