37. Sudoku Solver

题目:

Write a program to solve a Sudoku puzzle by filling the empty cells.

Empty cells are indicated by the character '.'.

You may assume that there will be only one unique solution.

A sudoku puzzle...

...and its solution numbers marked in red.

链接: http://leetcode.com/problems/sudoku-solver/

题解:

新加坡总理李显龙也做过的一题,还是用C做的,各种比特运算,巨快。思路就是DFS + Backtracking。在哪里回溯,怎样更好的构建DFS,需要多加练习。Knuth提到还有一种Dancing Links方法,用来构造回溯的,还不知道怎样使用。以及Boltzmann Machine。

Time Complexity - O(9m), Space Complexity -  O(m), m是'.'的数目。  

public class Solution {
    public void solveSudoku(char[][] board) {
        if(board == null || board.length == 0)
            return;
        trySolveSudokuDFS(board);
    }
    
    private boolean trySolveSudokuDFS(char[][] board) {
        for(int row = 0; row < 9; row++) {
            for(int col = 0; col < 9; col++) {
                if(board[row][col] == '.') {
                    for(char num = '1'; num <= '9'; num++) {
                        if(isValid(board, row, col, num)) {
                            board[row][col] = num;
                            if(trySolveSudokuDFS(board))            //DFS
                                return true;
                            else 
                                board[row][col] = '.';              //back-tracking
                        }
                    }
                    return false;
                }
            }
        }
        
        return true;
    }
    
    private boolean isValid(char[][] board, int row, int col, char c) {
        for(int i = 0; i < 9; i++)          //check if current col valid
            if(board[i][col] == c)
                return false;
        
        for(int j = 0; j < 9; j++)          //check if current row valid
            if(board[row][j] == c)
                return false;
        
        for(int i = row / 3 * 3; i < row / 3 * 3 + 3; i++) {          //check if current block valid
            for(int j = col / 3 * 3; j < col / 3 * 3 + 3 ; j++) {
                if(board[i][j] == c)
                    return false;
            }
        }
        
        return true;
    }
}

二刷:

根一刷使用的方法一样。主要还是DFS+ Backtracking。这里需要重新建立一个boolean类型的method canSolveSudoku,然后根据这个method来进行DFS。每次DFS之前,我们要先对'.'的位置进行预判断,检查是否能够放置从‘1’ - ‘9’的字符,假如可以,则我们设定这个位置的字符,之后进行DFS。否则我们尝试下一个字符。当DFS失败的时候,我们要backtracking,把这个位置的值重新设置为'.'。由于这个method canSolveSudoku是对于整个矩阵进行的dfs,所以在if block结束的时候我们就可以知道是否存在这样一个解, 我们可以在这里放一个 return false来提前终止循环,因为所有的条件我们都已经判断过了。

这里dfs的time complexity,  braching factor是9 ,深度是'.'的个数m,所以时间复杂度是O(9m),空间复杂度是O(9m) = O(m)。

Time Complexity - O(9m), Space Complexity - O(m)

Java:

public class Solution {
    public void solveSudoku(char[][] board) {
        canSolveSudoku(board);
    }
    
    private boolean canSolveSudoku(char[][] board) {
        if (board == null || board.length == 0) {
            return false;
        }
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board.length; j++) {
                if (board[i][j] == '.') {
                    for (char c = '1'; c <= '9'; c++) {
                    if (isCurrentBoardValid(board, i, j, c)) {
                            board[i][j] = c;
                            if (canSolveSudoku(board)) {
                                return true;
                            } else {
                                board[i][j] = '.';       // backtracking
                            }
                        }
                    }
                    return false;    
                }
            }
        }
        return true;
    }
    
    private boolean isCurrentBoardValid(char[][] board, int row, int col, char c) {
        for (int i = 0; i < board.length; i++) {
            if (board[i][col] == c) {
                return false;
            }
        }
        
        for (int j = 0; j < board[0].length; j++) {
            if (board[row][j] == c) {
                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 (board[i][j] == c) {
                    return false;
                }
            }
        }
        return true;
    }
}

Reference:

https://en.wikipedia.org/wiki/Dancing_Links 

http://www.csc.kth.se/utbildning/kth/kurser/DD143X/dkand12/Group6Alexander/final/Patrik_Berggren_David_Nilsson.report.pdf

https://leetcode.com/discuss/30482/straight-forward-java-solution-using-backtracking

原文地址:https://www.cnblogs.com/yrbbest/p/4436325.html