面试题目_经典面试题目「回溯算法」解数独
解數獨,理解二維遞歸是關鍵!
通知:我將公眾號文章和學習相關的資料整理到了Github :https://github.com/youngyangyang04/leetcode-master,方便大家在電腦上學習,可以fork到自己倉庫,順便也給個star支持一波吧!
37. 解數獨
題目地址:https://leetcode-cn.com/problems/sudoku-solver/
編寫一個程序,通過填充空格來解決數獨問題。
一個數獨的解法需遵循如下規則:
數字 1-9 在每一行只能出現一次。
數字 1-9 在每一列只能出現一次。
數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
空白格用 '.' 表示。
一個數獨。
答案被標成紅色。
提示:
- 給定的數獨序列只包含數字 1-9 和字符 '.' 。
- 你可以假設給定的數獨只有唯一解。
- 給定數獨永遠是 9x9 形式的。
思路
棋盤搜索問題可以使用回溯法暴力搜索,只不過這次我們要做的是「二維遞歸」。
怎么做二維遞歸呢?
大家已經跟著「代碼隨想錄」刷過了如下回溯法題目,例如:77.組合(組合問題),131.分割回文串(分割問題),78.子集(子集問題),46.全排列(排列問題),以及51.N皇后(N皇后問題),其實這些題目都是一維遞歸。
經典面試題目「回溯算法」N皇后問題 是因為每一行每一列只放一個皇后,只需要一層for循環遍歷一行,遞歸來來遍歷列,然后一行一列確定皇后的唯一位置。
本題就不一樣了,「本題中棋盤的每一個位置都要放一個數字,并檢查數字是否合法,解數獨的樹形結構要比N皇后更寬更深」。
因為這個樹形結構太大了,我抽取一部分,如圖所示:
回溯三部曲
- 遞歸函數以及參數
「遞歸函數的返回值需要是bool類型,為什么呢?」
因為解數獨找到一個符合的條件(就在樹的葉子節點上)立刻就返回,相當于找從根節點到葉子節點一條唯一路徑,所以需要使用bool返回值,這一點在回溯算法:N皇后問題中已經介紹過了,一樣的道理。
代碼如下:
bool?backtracking(vector>&?board)- 遞歸終止條件
本題遞歸不用終止條件,解數獨是要遍歷整個樹形結構尋找可能的葉子節點就立刻返回。
「不用終止條件會不會死循環?」
遞歸的下一層的棋盤一定比上一層的棋盤多一個數,等數填滿了棋盤自然就終止(填滿當然好了,說明找到結果了),所以不需要終止條件!
「那么有沒有永遠填不滿的情況呢?」
這個問題我在遞歸單層搜索邏輯里在來講!
- 遞歸單層搜索邏輯
在樹形圖中可以看出我們需要的是一個二維遞歸(也就是兩個for循環嵌套著遞歸)
「一個for循環遍歷棋盤的行,一個for循環遍歷棋盤的列,一行一列確定下來之后,遞歸遍歷這個位置放9個數字的可能性!」
代碼如下:(「詳細看注釋」)
bool?backtracking(vector>&?board)?{????for?(int?i?=?0;?i?「注意這里return false的地方,這里放return false 是有講究的」。
因為如果一行一列確定下來了,這里嘗試了9個數都不行,說明這個棋盤找不到解決數獨問題的解!
那么會直接返回, 「這也就是為什么沒有終止條件也不會永遠填不滿棋盤而無限遞歸下去!」
判斷棋盤是否合法
判斷棋盤是否合法有如下三個維度:
- 同行是否重復
- 同列是否重復
- 9宮格里是否重復
代碼如下:
bool?isValid(int?row,?int?col,?char?val,?vector>&?board)?{????for?(int?i?=?0;?i?最后整體代碼如下:
C++代碼
class?Solution?{private:bool?backtracking(vector>&?board)?{????for?(int?i?=?0;?i?>&?board)?{????for?(int?i?=?0;?i?>&?board)?{????????backtracking(board);????}};總結
解數獨可以說是非常難的題目了,如果還一直停留在單層遞歸的邏輯中,這道題目可以讓大家瞬間崩潰。
所以我在開篇就提到了「二維遞歸」,這也是我自創詞匯,希望可以幫助大家理解解數獨的搜索過程。
一波分析之后,在看代碼會發現其實也不難,唯一難點就是理解「二維遞歸」的思維邏輯。
「這樣,解數獨這么難的問題,也被我們攻克了」。
「恭喜一路上堅持打卡的錄友們,回溯算法已經接近尾聲了,接下來就是要一波總結了」。
更多精彩點擊下方了解更多!
總結
以上是生活随笔為你收集整理的面试题目_经典面试题目「回溯算法」解数独的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xshell 软件的窗口一直是置顶 调整
- 下一篇: zabbix的安装