LeetCode刷题笔记(Sudoku Solver)

今天刷了一道题感觉难度有点大,不过该题的标签是“hard”,下面就和大家分享一下经验吧!

题目如下:

题意分析:

本题为著名的求解数独问题:请为给定的9*9棋盘中‘.’处(可视作图中的空格)填入1-9之间的数字,使得1-9之间的数字在横向、纵向以及3*3的子平面均只出现一次。

注:① 题目给定的棋盘有唯一解 ② 棋盘大小总为9*9

方法一(递归回溯法①)

本题与N-Queens的思路有些相似,均采取“试凑法”。对于棋盘中每个需要填数字的格子均试放从1到9的数,且每放入一个数都通过is_Valid函数来判定其是否合法,如果合法就继续下一次递归,结束时把数字设回'.'。

注:判断新放入的数是否合法时,由于之前加进的数都是合法的,所以只需要判定新放入的数字是否合法即可。

解题代码如下:

class Solution{
private:        
    bool findsolveSudoku( vector<vector<char>>& board, int i, int j ){
        if ( i == 9 ) return true;
        if ( j >= 9 ) return findsolveSudoku( board, i+1, 0 );

        if( board[i][j] == '.' ){
            for ( int k = 1; k < 10; k++ ) {
                board[i][j] = (char)(k + '0');
                if ( is_Valid( board, i ,j ) ){
                    if ( findsolveSudoku( board, i, j + 1 ) ) return true;
                }
                board[i][j] = '.';
            }
        }
        else{
            return  findsolveSudoku( board, i, j+1 );
        }
        //数独无解
        return false;
    }
    bool is_Valid( vector<vector<char>>& board, int row ,int col ){
        for ( int i = 0; i < 9; i++ ) {
            if ( i != col && board[row][i] == board[row][col] ) return false;
        }

        for ( int i = 0; i < 9; i++ ) {
            if ( i != row && board[i][col] == board[row][col] ) return false;
        }

        for ( int i = row / 3 * 3; i < row / 3 * 3 + 3; i++ ) {
            for ( int j = col / 3 * 3; j < col / 3 * 3 +3; j++ ) {
                if ( i != row && j != col && board[i][j] == board[row][col]) return false;
            }
        }
        return true;
    }

public:
    void solveSudoku( vector<vector<char>>& board ){
        if ( board.empty() || board.size() != 9 ||  board[0].size() != 9 ) return;
        findsolveSudoku( board, 0, 0 );
    }
};

提交后的结果如下:

 

方法二(递归回溯法②)

这是刘宇波老师在Github(https://github.com/liuyubobobo/Play-Leetcode/tree/master)给出的版本,其实个人还是比较喜欢刘宇波老师讲的课,建议大家可以去听听他讲的《玩转算法面试》。

解题代码如下:

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {

        vector<vector<bool>> row(9, vector<bool>(10, false));
        vector<vector<bool>> col(9, vector<bool>(10, false));
        vector<vector<bool>> block(9, vector<bool>(10, false));
        for(int i = 0; i < 9; i ++)
            for(int j = 0; j < 9; j ++)
                if(board[i][j] != '.'){
                    row[i][board[i][j] - '0'] = true;
                    col[j][board[i][j] - '0'] = true;
                    block[i / 3 * 3 + j / 3][board[i][j] - '0'] = true;
                }

        for(int i = 0; i < 81; i ++)
            if(board[i / 9][i % 9] == '.'){
                assert(dfs(board, i, row, col, block));
                return;
            }
    }

private:
    bool dfs(vector<vector<char>>& board, int pos,
             vector<vector<bool>>& row, vector<vector<bool>>& col,
             vector<vector<bool>>& block){

        if(pos == 81)
            return true;

        int next = pos + 1;
        for(; next < 81; next ++)
            if(board[next / 9][next % 9] == '.')
                break;

        int x = pos / 9, y = pos % 9;
        for(int i = 1; i <= 9; i ++)
            if(!row[x][i] && !col[y][i] && !block[x / 3 * 3 + y / 3][i]){
                row[x][i] = true;
                col[y][i] = true;
                block[x / 3 * 3 + y / 3][i] = true;
                board[x][y] = '0' + i;

                if(dfs(board, next, row, col, block))
                    return true;

                row[x][i] = false;
                col[y][i] = false;
                block[x / 3 * 3 + y / 3][i] = false;
                board[x][y] = '.';
            }
        return false;
    }
};

提交后的结果如下:

 

 

 

日积月累,与君共进,增增小结,未完待续。  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值