###### tags: `LeetCode` `Recursion` `Hard` `DFS` # LeetCode #37 [Sudoku Solver](https://leetcode.com/problems/sudoku-solver/) ### (Hard) 編寫一個程式,通過填充空格來解決數獨問題。 數獨的解法需 遵循如下規則: 數字 1-9 在每一行只能出現一次。 數字 1-9 在每一列只能出現一次。 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。 (請參考示例圖) 數獨部分空格內已填入了數字,空白格用 '.' 表示。 ![](https://i.imgur.com/8dB3ono.png) ![](https://i.imgur.com/noLz41I.png) --- 要點有二: 1. 判斷插入數字的合法性(同行無重複、同列無重複、同九宮格無重複) 2. 如何遍歷每一個點 第1點很好解決, 重點是第2點。 第2點的解決方法是通過類似進位的方式, 每當跑完最後一行時(j==9), 就進位, 改為嘗試下一列的第一行的數(i=i+1, j=0), 而當列數到達9時(0~8共9列), 則代表遍歷完整個數獨, 此時回傳真。 另外, 與其他DFS不同的點在於終止條件, 這題的遞迴函式類別為bool而非void(當整個DFS跑完後, 就必須回傳, 因為答案只有一個而且所有數獨盤共享同一個參考, 若不及時回傳會把正確答案給改掉), 遞迴呼叫下一行(i, j+1), 而回傳條件則是當下一遞迴回傳true時回傳true, 否則回傳false。 若遍歷到的數獨格已存在數字, 則該數字為預先填好的題目數字, 此時直接跳過可以省去時間。 --- ``` class Solution { public: void solveSudoku(vector<vector<char>>& board) { dfs(board, 0, 0); } bool isvalid(vector<vector<char>>& board, int i, int j, char c){ int ii=i-i%3; int jj=j-j%3; for(int k=0;k<9;k++)if(board[k][j]==c)return false; for(int k=0;k<9;k++)if(board[i][k]==c)return false; for(int x=ii;x<ii+3;x++){ for(int y=jj;y<jj+3;y++){ if(board[x][y]==c)return false; } } return true; } bool dfs(vector<vector<char>>& board, int i, int j){ if(i==9)return true; if(j==9)return dfs(board, i+1, 0); if(isdigit(board[i][j]))return dfs(board, i, j+1); for(char c='1';c<='9';c++){ if(isvalid(board, i, j, c)){ board[i][j]=c; if(dfs(board, i, j+1))return true; board[i][j]='.'; } } return false; } }; ```