037J. Sudoku Solver

https://leetcode.com/problems/sudoku-solver/

Method Best

某种程度上来说,这个题比上一题还简单点。真是会者不难,难者不会。
目前还是菜鸡,Backtracking好写但是难想,而且想到用BackTracking
就挺有技术难度的。

大致的想法就是,从棋盘左上到右下遍历,遇到已经有数字的就跳过,然后
对空位尝试所有的可能。当然每次尝试也都需要符合数独的规则,由此可以想到
至少需要写一个判定该位字符是否符合数独规则的函数。而这个函数比较好写,
输入应当是现在的棋盘实例,当下的行列数和测试的值。剩下的都在code中。
不论如何这个题猛一遇到还是蛮难的。
class Solution {
    public void solveSudoku(char[][] board) {
        // Suppose Sudoku Board is promised to have at least one solution.
        scanner(board, 0, 0); // Start from the (0,0)
    }
    // scanner is a helper function
    // 规定从左到右,自上而下的检查数独棋盘
    public boolean scanner(char[][] board, int row, int column){
        // we have reached the end of the board, return true;
        if(row == 9) return true;
        // if we've reached the end of one row, go to the beginning of next row.
        // 如果后面错我们就继承这个错向上传递,对了也一样。
        if(column == 9 ) return scanner(board, row + 1, 0);
        // if it is taken by some number already, check next position
        // 同上
        if(board[row][column] != '.') return scanner(board, row, column + 1);
        // edge cases都考虑了,开始穷举
        // try 1 - 9
        for(char c = '1'; c <= '9'; c++){
            //最起码要符合当下的数独形势,不行就换下一个试试
            // 注意此时棋盘上该位置仍为空
            if(!validOrNot(board,row,column,c)) continue;
            // 如果暂时还行就先赋值试试
            board[row][column] = c;
            // 赋值之后向后传递,如果直到最后都测试成功,那么就向上返回true。
            if(scanner(board,row,column+1)) return true;
            // 如果到最后没有测试成功,赶快把这位置复原成空,下一次循环再赋值一个新的试试
            board[row][column] = '.';
        }
        //如果从1-9都试了,都不行,那么就告诉上一级,你们前面哪里搞错了,试试别的。
        return false;
    }

    // try to put c at (m,n), check if it is valid.
    public boolean validOrNot(char[][] board, int row, int column, char c){
        // 由于现在c还没有赋值给该位置,可以放心大胆的对比。
        // 检查三个部分,row, column, sub-box,是否出现过该c.

        //检查row 和 column
        for(int i = 0; i < 9; i++){
            if( board[row][i] == c || board[i][column] == c) return false;
        }

        // sub-box的左上角位置 (m,n)
        int m = row - row%3, n = column - column%3;
        // 检查 sub-box
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                if(board[m+i][n+j] == c) return false;
            }
        }
        //检查完了 没啥问题 返回true吧
        return true;

    }
}

还可以为每行每列每个 box 都建立一个 Set. 注意这个 Set 一定要先扫一遍放进去,不然会犯错。

class Solution {
    boolean[][] rowSets;
    boolean[][] colSets;
    boolean[][] boxSets;

    public void solveSudoku(char[][] board) {
        rowSets = new boolean[9][10];
        colSets = new boolean[9][10];
        boxSets = new boolean[9][10];
        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < 9; j++) {
                if( board[i][j] == '.') continue;
                int number = board[i][j] - '0';
                int box = i/3*3 + j/3;
                rowSets[i][number] = true;
                colSets[j][number] = true;
                boxSets[box][number] = true;
            }
        }
        scanner(board, 0, 0);
    }
    public boolean scanner(char[][] board, int row, int col){
        if(row == 9) return true;
        if(col == 9 ) return scanner(board, row + 1, 0);
        if(board[row][col] != '.') return scanner(board, row, col + 1);

        int box = row/3 * 3 + col/3;

        for(char c = '1'; c <= '9'; c++){
            int number = c - '0';
            if(rowSets[row][number] || colSets[col][number] || boxSets[box][number]) continue;

            board[row][col] = c;
            rowSets[row][number] = true;
            colSets[col][number] = true;
            boxSets[box][number] = true;

            if(scanner(board,row,col+1)) return true;

            board[row][col] = '.';
            rowSets[row][number] = false;
            colSets[col][number] = false;
            boxSets[box][number] = false;
        }
        return false;
    }
}
class Solution {
    private boolean[][] rows;
    private boolean[][] cols;
    private boolean[][] boxes;
    public void solveSudoku(char[][] board) {
        this.rows = new boolean[9][9];
        this.cols = new boolean[9][9];
        this.boxes = new boolean[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') continue;
                int val = (int) (board[i][j] - '1');
                int box = (i / 3) * 3 + j / 3;
                rows[i][val] = true;
                cols[j][val] = true;
                boxes[box][val] = true;
            }
        }
        helper(board, 0, 0);
    }
    private boolean helper(char[][] board, int i, int j) {
        if (i == 9) return true;
        if (i < 0 || i > 8 || j < 0 || j > 8) return false;
        if (board[i][j] != '.') {
            int nextRow = (j == 8) ? i + 1 : i;
            int nextCol = (j == 8) ? 0 : j + 1;
            return helper(board, nextRow, nextCol);
        }
        int box = (i / 3) * 3 + j / 3;
        for (int n = 0; n < 9; n++) {
            if (rows[i][n] || cols[j][n] || boxes[box][n]) continue;
            rows[i][n] = true;
            cols[j][n] = true;
            boxes[box][n] = true;
            board[i][j] = (char) ('1' + n);
            int nextRow = (j == 8) ? i + 1 : i;
            int nextCol = (j == 8) ? 0 : j + 1;
            if (helper(board, nextRow, nextCol)) return true;
            board[i][j] = '.';
            rows[i][n] = false;
            cols[j][n] = false;
            boxes[box][n] = false;
        }
        return false;
    }
}

Last updated

Was this helpful?