1. 程式人生 > >解數獨

解數獨

編寫一個程式,通過已填充的空格來解決數獨問題。

一個數獨的解法需遵循如下規則:

數字 1-9 在每一行只能出現一次。
數字 1-9 在每一列只能出現一次。
數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
空白格用 ‘.’ 表示。

一個數獨。

答案被標成紅色。

Note:

給定的數獨序列只包含數字 1-9 和字元 ‘.’ 。
你可以假設給定的數獨只有唯一解。
給定數獨永遠是 9x9 形式的。

方法:回溯法
思路:
1,將陣列中每一個空格置換為0-9的數字;
2,然後判斷填入這個數字後,該數字對應的行,列和九宮格是否滿足不重複的條件;
3,如果當前填入的數字滿足,就繼續填入下一個數字,下一個數字又從0-9中嘗試,如果有滿足的數字就說明該數字可用,如果沒有,則將該數字又重新置為空格,如此迴圈往復;
4,如果將所有的數字都嘗試了還是沒有合適的額,那說明本問題無解,返回false;

public class Solution {
    public void solveSudoku(char[][] board) {
        if(board == null||board.length==0)
            return ;
        helper(board);
    }
    private boolean helper(char[][] board){
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[0].length;j++){
                if(board[i][j]=='.'){
                    for(char num = '1';num<='9';num++){
                        if(isValid(board,i,j,num)){
                            board[i][j]=num;
                            if(helper(board)){
                                return true;
                            }else{
                                board[i][j]='.';
                            }
                        }
                    }
                    return false;//全部放過後還是沒有正確的
                }
            }
        }
        return true;//全部遍歷後找不到有‘.’的,都寫完啦,說明對了
    }
    private boolean isValid(char[][] board,int i,int j,char c){
        for(int row=0;row<9;row++){//行是否合法
            if(board[row][j]==c)
                return false;
        }
        for(int col=0;col<9;col++){//列是否合法
            if(board[i][col]==c)
                return false;
        }
        for(int row=i/3*3;row<i/3*3+3;row++){//小的block是否合法
            for(int col=j/3*3;col<j/3*3+3;col++){
                if(board[row][col]==c)
                    return false;
            }
        }
        return true;
    }
}

注意:
1,遞迴時,如果下個數字不滿足要做撤銷動作,將當前的數字重新置為空格;
2,小九宮格迴圈條件判斷時,是需要先進行除法運算拿到當前行或者列的起始行/列,再與此基礎上判斷在這個九宮格中是否滿足。