leetcode37 解數獨問題 hard

Sunissopretty發表於2020-12-16

編寫一個程式,通過填充空格來解決數獨問題。
一個數獨的解法需遵循如下規則:
數字 1-9 在每一行只能出現一次。
數字 1-9 在每一列只能出現一次。
數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
空白格用 ‘.’ 表示。

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

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/sudoku-solver

作為一個剛剛起步演算法的小弱雞,稍微記錄一下自己對於這題的設計思路吧,沒有嘗試高大上的辦法,我只用了最簡單的回溯辦法,但是這道題確實加深了我對於回溯的理解。
基本思路是對於一個數獨矩陣,設計一個函式helper(board,row,col),對於board[row][col]按進行1-9窮舉,並判斷isvalid,如果這一位填的數字滿足數獨矩陣條件,那麼就判斷helper(board,row,col+1),這裡需要思考的是我們希望這個遞迴函式的意義是什麼,我的回答是,我希望輸入board,row,col能夠判斷這之後的整個數獨能不能填完,以此為基點思考下去就會遇到一個問題:
最開始我設計的輔助函式是一個無返回的void函式,但是我發現這樣子無法知道後一位helper(board,row,col+1)是否能夠填完,所以將函式改為bool函式,那麼helper(board,row,col)的返回值判斷思路如下:
如果board[row][col]填了數字或者能填數字,那麼就判斷helper(board,row,col+1)是否是true,如果是那麼返回true;不是那就說明這一位填的數字不對,那就換一個數字,如果窮舉完9個數字都沒有返回true,那就說明helper(board,row,col)無法完成數獨,所以return false。
回溯的思想則體現在中間每次將choose的數字改回’.'的過程。

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        helper(board,0,0);
    }
    //輸入位置返回是否能填成功
    bool helper(vector<vector<char>>& board,int row,int col){
        if(row==8&&col==9){
            //base case
            return true;
        }
        //位置變化
        if(col==9){
            col=0;
            row++;
        }
        //如果已經有數字了
        if(board[row][col]!='.') return helper(board,row,col+1);
        //沒數字的話窮舉此位置1-9
        else{
            for(int i=1;i<10;i++){
                //choose
                board[row][col]=(char)(i+'0');
                bool flag=isvalid(row,col,board);
                if(flag) {
                    if(helper(board,row,col+1)) return true;
                }
                //unchoose
                board[row][col]='.';
            }
            //如果9個數都舉完,仍然不能返回true,說明是之前選的數字出錯了,因此返回false
            return false;
        }
    }
    bool isvalid(int row,int col,vector<vector<char>>& board){
        int num=board[row][col];
        for(int i=0;i<9;i++){
            if(i==col) continue;
            if(board[row][i]==num) return false;
        }
        for(int i=0;i<9;i++){
            if(i==row) continue;
            if(board[i][col]==num) return false;
        }
        int a=row/3;
        int b=col/3;
        for(int i=a*3;i<(a+1)*3;i++){
            for(int j=b*3;j<(b+1)*3;j++){
                if(row==i&&col==j) continue;
                if(board[i][j]==num) return false;
            }
        }
        return true;
    }
};

相關文章