乘風破浪:LeetCode真題_037_Sudoku Solver

 乘風破浪:LeetCode真題_037_Sudoku Solver

1、前言

   此次咱們對於上次的模型作一個擴展並求解。java

2、Sudoku Solver

2.1 問題

2.2 分析與解決

    這道題讓咱們按照規則,填寫數獨表上的內容,而且已知假設答案是惟一的。這裏咱們直到一個3*3的方格內的數字不能重複,所以需要填寫完成,就須要全部的數字,所以咱們能夠嘗試使用圖遍歷中的深度優先和廣度優先遍從來不斷地試探,直到獲得最後的結果。一樣的遞歸也能達成上面的要求。算法

class Solution {
    int[][] hCounts;
    int[][] vCounts;
    int[][][] sqCounts;
    public void solveSudoku(char[][] board) {
        hCounts = new int[9][9];
        vCounts = new int[9][9];
        sqCounts = new int[3][3][9];
        for (int row=0;row<9;row++) {
            for (int col=0;col<9;col++) 
                if (board[row][col] != '.') 
                    set(board, row, col, board[row][col]);
        }
        solve(board, 0, 0);
    }
    private boolean solve(char[][] board, int row, int col) {
        if (row == board.length) 
            return true;
        if (col == board[0].length) 
            return solve(board, row+1, 0);
        if (board[row][col] != '.')
            return solve(board, row, col+1);
        
        for (int i=1;i<10;i++) {
            char n = (char)('0' + i);
            if (canAdd(row, col, n)) {
                set(board, row, col, n);
                if (solve(board, row, col+1)) 
                    return true;
                unset(board, row, col, n);
            }
        }
        return false;
    }
    private boolean canAdd(int row, int col, char c) {
        int n = c-'0'-1;
        return hCounts[row][n] == 0 && vCounts[col][n] == 0 && sqCounts[row/3][col/3][n] == 0;
    }
    private void set(char[][] board, int row, int col, char c) {
        board[row][col] = c;
        int n = c-'0'-1;
        hCounts[row][n]++;
        vCounts[col][n]++;
        sqCounts[row/3][col/3][n]++;
    }
    private void unset(char[][] board, int row, int col, char c) {
        board[row][col] = '.';
        int n = c-'0'-1;
        hCounts[row][n]--;
        vCounts[col][n]--;
        sqCounts[row/3][col/3][n]--;
    }
}

    這道題的算法能夠說是很是經典的,進行了一些抽象,首先是初始化,經過三個數組來檢驗能不能添加元素進去。方法也很簡單,若是存在過某個數值,就加一,而後再添加的時候須要判斷一下是否是可以加入進去。數組

 1     private boolean canAdd(int row, int col, char c) {
 2         int n = c-'0'-1;
 3         return hCounts[row][n] == 0 && vCounts[col][n] == 0 && sqCounts[row/3][col/3][n] == 0;
 4     }
 5     private void set(char[][] board, int row, int col, char c) {
 6         board[row][col] = c;
 7         int n = c-'0'-1;
 8         hCounts[row][n]++;
 9         vCounts[col][n]++;
10         sqCounts[row/3][col/3][n]++;
11     }

    以後咱們從最開始的[0,0]按行遍歷,經過遞歸算法,若是能將字符加入進去就加入,繼續調用,不能的話就撤回,而後繼續遍歷,先對每一行的每一列的元素進行遍歷,當完成以後遍歷下一行,直至結束。spa

 1     private boolean solve(char[][] board, int row, int col) {
 2         if (row == board.length) //已經遍歷到表外了,結束,成功。  3             return true;  4         if (col == board[0].length) //開始下一行  5             return solve(board, row+1, 0);  6         if (board[row][col] != '.') //不爲.則繼續下一列。  7             return solve(board, row, col+1);  8         
 9         for (int i=1;i<10;i++) {
10             char n = (char)('0' + i);
11             if (canAdd(row, col, n)) { 12  set(board, row, col, n); 13                 if (solve(board, row, col+1)) 14                     return true; 15  unset(board, row, col, n);//不成功,回退 16  } 17         }
18         return false; //最後都沒成功,返回false 19     }

3、總結

    涉及到圖的問題,讓咱們想到了八皇后問題,一樣的聯想到這個題的解法。code

相關文章
相關標籤/搜索