37. 解数独

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

空白格用 '.' 表示。

一个数独。

答案被标成红色。

Note:

  • 给定的数独序列只包含数字 1-9 和字符 '.' 。
  • 你可以假设给定的数独只有唯一解。
  • 给定数独永远是 9x9 形式的。

思路:这题目用dfs来做,81个小格一共构成了81层,每一层有9个分支,分别取1-9之间的数。

方法1:采用哈希表的方法,要注意以下几点:

1、一开始要对原始棋盘上的数字进行标记,采用original函数。

2、dfs之前修改棋盘和use上的数字,dfs之后记得恢复棋盘和use上的数字。

class Solution {
public:
    int use1[9][9] = {0}, use2[9][9] = {0}, use3[9][9] = {0};
    void original(vector<vector<char>>& board) {//对棋盘上的原始数据进行标记
        for (int i = 0; i < 9; ++i){
            for (int j = 0; j < 9; ++j){
                char x = board[i][j];
                if (x == '.') continue;
                int aa = int(x - '0' - 1);
                int k = (i / 3) * 3 + j / 3;//注意box的i,j坐标要和第几个box,也就是use3中的哪一行对应好
                use1[i][aa] = use2[j][aa] = use3[k][aa] = 1;
            }
        }
    }

    bool isValidSudoku(vector<vector<char>>& board, int i, int j, char c) {//每次验证当前棋盘上的数字是否是有效的
        int aa = int(c - '0' - 1);
        int k = (i / 3) * 3 + j / 3;//注意box的i,j坐标要和第几个box,也就是use3中的哪一行对应好
        if (use1[i][aa] || use2[j][aa] || use3[k][aa]) return false;
        use1[i][aa] = use2[j][aa] = use3[k][aa] = 1; //递归前修改
        return true;
    }

    bool dfs(int i, int j, vector<vector<char>>& board){//深搜
        if (i == 8 && j == 9)  return true;
        if (j == 9){
            ++i;
            j = 0;
        }
        if (board[i][j] != '.')	return dfs(i, j + 1, board);//直接跳到下一层
        else{
            for (char c = '1'; c <= '9'; ++c){
                if (isValidSudoku(board, i, j, c)){
                    board[i][j] = c;       //递归前修改
                    if (dfs(i, j + 1, board)) return true;
                    board[i][j] = '.';    //递归后恢复
                    int aa = int(c - '0' - 1);
                    int k = (i / 3) * 3 + j / 3;
                    use1[i][aa] = use2[j][aa] = use3[k][aa] = 0;
                }
            }
            return false;
        }
    }

    void solveSudoku(vector<vector<char>>& board) {
        isValidSudoku(board);
        dfs(0, 0, board);
    }
};

方法2:不用哈希表,直接暴力:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board, int i, int j, char c) {//暴力判断是否有效
        for (int k = 0; k < 9; ++k){
            if (board[i][k] == c) return false;
            if (board[k][j] == c) return false;
            if(board[(i / 3) * 3 + k/3][(j/3)*3+k%3]==c) return false;
        }
        return true;
    }

    bool dfs(vector<vector<char>>& board){
        int i = 0, j = 0;
        for (i = 0; i < 9; ++i){
            for (j = 0; j < 9; ++j){
                if (board[i][j] == '.') break;
            }
            if (board[i][j] == '.') break;
        }//找到第一个'.'
        if (i == 9) return true;//说明棋盘填满了
        for (char c = '1'; c <= '9'; ++c){
            if (isValidSudoku(board, i, j, c)){
                board[i][j] = c;       //递归前修改
                if (dfs(board)) return true;
                board[i][j] = '.';     //递归后恢复
            }
        }
        return false;
    }

    void solveSudoku(vector<vector<char>>& board) {
        dfs(board);
    }
};

猜你喜欢

转载自blog.csdn.net/scarlett_guan/article/details/80065338