leetcode 37. 解数独 思考分析
目錄
- 題目
- 核心思路的不斷細(xì)化
- 1、核心框架
- 2、考慮到每個(gè)位置的工作
- 3、考慮到到達(dá)最后一列、該位置的數(shù)已經(jīng)預(yù)置的情況
- 4、判斷是否符合規(guī)則的函數(shù)
- 5、確定遞歸終止條件+確定函數(shù)返回值
- AC代碼
題目
編寫一個(gè)程序,通過(guò)填充空格來(lái)解決數(shù)獨(dú)問(wèn)題。
一個(gè)數(shù)獨(dú)的解法需遵循如下規(guī)則:
1、數(shù)字 1-9 在每一行只能出現(xiàn)一次。
2、數(shù)字 1-9 在每一列只能出現(xiàn)一次。
3、數(shù)字 1-9 在每一個(gè)以粗實(shí)線分隔的 3x3 宮內(nèi)只能出現(xiàn)一次。
空白格用 ‘.’ 表示。
| 一個(gè)數(shù)獨(dú)。 | 答案被標(biāo)成紅色。 |
給定的數(shù)獨(dú)序列只包含數(shù)字 1-9 和字符 ‘.’ 。
你可以假設(shè)給定的數(shù)獨(dú)只有唯一解。
給定數(shù)獨(dú)永遠(yuǎn)是 9x9 形式的。
核心思路的不斷細(xì)化
算法的核心思路就是對(duì)每一個(gè)空著的格子窮舉 1 到 9,如果遇到不合法的數(shù)字(在同一行或同一列或同一個(gè) 3×3 的區(qū)域中存在相同的數(shù)字)則跳過(guò),如果找到一個(gè)合法的數(shù)字,則繼續(xù)窮舉下一個(gè)空格子。
寫出核心框架:
1、核心框架
void solveSudoku(vector<vector<char>>& board) {backtrack(board, 0, 0); }void backtrack(vector<vector<char>>& board, int hang, int lie) {// 就是對(duì)棋盤的每個(gè)位置進(jìn)行窮舉for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 做選擇backtrack(board, i, j);// 撤銷選擇}} }2、考慮到每個(gè)位置的工作
對(duì)于每個(gè)位置有1~9的選擇,這樣就變成了3重嵌套循環(huán)。
void backtrack(vector<vector<char>>& board, int hang, int lie) {// 就是對(duì)每個(gè)位置進(jìn)行窮舉for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {for (char ch = '1'; ch <= '9'; ch++) {// 做選擇board[i][j] = ch;// 繼續(xù)窮舉下一列,backtrack(board, i, j + 1);// 撤銷選擇board[i][j] = '.';}}} }3、考慮到到達(dá)最后一列、該位置的數(shù)已經(jīng)預(yù)置的情況
1、當(dāng)lie到達(dá)超過(guò)最后一個(gè)索引時(shí),轉(zhuǎn)為增加hang開(kāi)始窮舉下一行。
2、如果當(dāng)前位置元素不為“.”,那么跳過(guò)即可。
3、窮舉的時(shí)候如果遇到符合規(guī)則的數(shù)字,填入,否則跳過(guò)。
4、判斷是否符合規(guī)則的函數(shù)
規(guī)則如下:
1、數(shù)字 1-9 在每一行只能出現(xiàn)一次。
2、數(shù)字 1-9 在每一列只能出現(xiàn)一次。
3、數(shù)字 1-9 在每一個(gè)以粗實(shí)線分隔的 3x3 宮內(nèi)只能出現(xiàn)一次。
翻譯成函數(shù):
注意這里對(duì)第3個(gè)規(guī)則的描述:
下面是這個(gè)式子的含義,并且將i=0~8模擬了一下:
5、確定遞歸終止條件+確定函數(shù)返回值
如果遞歸完最后一行,那么我們就可以返回我們的結(jié)果了。
如果找到一個(gè)解我們的任務(wù)就結(jié)束了,本題并沒(méi)有要求找到所有解。
如果一個(gè)位置遍歷完所有數(shù)字,都不符合,這說(shuō)明此路不通,應(yīng)該及時(shí)返回false。
如果每個(gè)位置都遍歷過(guò)了,結(jié)果都沒(méi)有返回true,說(shuō)明,這個(gè)數(shù)獨(dú)棋盤沒(méi)有解,返回false。
所以使用bool類型的值作為返回值:
完整的回溯函數(shù)代碼應(yīng)該如下:
bool backtrack(vector<vector<char>>& board, int hang, int lie) {//遍歷完這一行最后一列,轉(zhuǎn)而遍歷下一行if(lie==9){return backtrack(board, hang+1, 0);}//找到一個(gè)解,返回if(hang == 9) return true;// 就是對(duì)每個(gè)位置進(jìn)行窮舉for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 如果該位置是預(yù)設(shè)的數(shù)字,不用我們操心if (board[i][j] != '.') {return backtrack(board, i, j + 1);} //如果不是預(yù)置的數(shù)字for (char ch = '1'; ch <= '9'; ch++) {// 如果遇到符合規(guī)則的數(shù)字,填入if (isValid(board, i, j, ch)){// 做選擇board[i][j] = ch;// 繼續(xù)窮舉下一列,如果找到了一個(gè)解,立即結(jié)束if(backtrack(board, i, j + 1) == true) return true;// 撤銷選擇board[i][j] = '.';}}// 窮舉完 1~9,依然沒(méi)有找到可行解,此路不通return false;}}return false; }AC代碼
class Solution { public:// 判斷 board[i][j] 是否可以填入 nbool isValid(vector<vector<char>>& board, int hang, int lie, char n) {for (int i = 0; i < 9; i++) {// 判斷行是否存在重復(fù)if (board[hang][i] == n) return false;// 判斷列是否存在重復(fù)if (board[i][lie] == n) return false;// 判斷 3 x 3 方框是否存在重復(fù)if (board[(hang/3)*3 + i/3][(lie/3)*3 + i%3] == n)return false;}return true;}bool backtrack(vector<vector<char>>& board, int hang, int lie) {//遍歷完這一行最后一列,轉(zhuǎn)而遍歷下一行if(lie==9){return backtrack(board, hang+1, 0);}//找到一個(gè)解,返回if(hang == 9) return true;// 就是對(duì)每個(gè)位置進(jìn)行窮舉for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 如果該位置是預(yù)設(shè)的數(shù)字,不用我們操心if (board[i][j] != '.') {return backtrack(board, i, j + 1);} //如果不是預(yù)置的數(shù)字for (char ch = '1'; ch <= '9'; ch++) {// 如果遇到符合規(guī)則的數(shù)字,填入if (isValid(board, i, j, ch)){// 做選擇board[i][j] = ch;// 繼續(xù)窮舉下一列,如果找到了一個(gè)解,立即結(jié)束if(backtrack(board, i, j + 1) == true) return true;// 撤銷選擇board[i][j] = '.';}}// 窮舉完 1~9,依然沒(méi)有找到可行解,此路不通return false;}}return false;}void solveSudoku(vector<vector<char>>& board) {backtrack(board, 0, 0);return;} };總結(jié)
以上是生活随笔為你收集整理的leetcode 37. 解数独 思考分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: leetcode 51. N 皇后 思考
- 下一篇: leetcode 198. 打家劫舍 思