LeetCode 36有效的数独37解数独(八皇后问题)
公眾號:bigsai 回復進群加入打卡
有效的數獨
判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。
數字 1-9 在每一行只能出現一次。
數字 1-9 在每一列只能出現一次。
數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
上圖是一個部分填充的有效的數獨。
數獨部分空格內已填入了數字,空白格用 ‘.’ 表示。
示例 1:
輸入: [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"] ] 輸出: true示例 2:
輸入: [["8","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"] ] 輸出: false解釋:
除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
但由于位于左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。
說明:
一個有效的數獨(部分已被填充)不一定是可解的。
只需要根據以上規則,驗證已經填入的數字是否有效即可。
給定數獨序列只包含數字 1-9 和字符 ‘.’ 。
給定數獨永遠是 9x9 形式的。
分析
本題的話就是要選擇合理的方式去判斷是否有效。是否有效需要滿足三個維度:
- 行是否有效
- 列是否有效
- 3x3的格子內是否有效。
而每一個維度考慮的問題都是有相關性的,例如這一行的1-9每個數字只能出現一次,這一列也是,這個3x3也是。這樣的話我們就可以通過三個boolean數組來判斷各自對應的區間是否滿足。因為每個區間每個數字最多只能出現一次,所以判斷所有次數滿足條件即可,一旦不滿足就停止返回false。
當然這個有點麻煩的就是需要求當前是在第幾個3x3的小方格內,經過思考(i/3)*3+j/3這個表達式可以很好的表示。
實現代碼為:
public boolean isValidSudoku(char[][] board) {boolean hang[][]=new boolean[9][9];//第一個是 9個坑,第二個是數字位置boolean lie[][]=new boolean[9][9];boolean fangge[][]=new boolean[9][9];for(int i=0;i<board.length;i++){for(int j=0;j<board[0].length;j++){if(board[i][j]=='.') {continue;}int num=board[i][j]-'1';if(hang[i][num]||lie[j][num]||fangge[(i/3)*3+j/3][num]){return false;}else {hang[i][num]=true;lie[j][num]=true;fangge[(i/3)*3+j/3][num]=true;}}}return true;}解數獨
題目描述:
編寫一個程序,通過填充空格來解決數獨問題。
一個數獨的解法需遵循如下規則:
數字 1-9 在每一行只能出現一次。
數字 1-9 在每一列只能出現一次。
數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
空白格用 ‘.’ 表示。
一個數獨。
答案被標成紅色。
提示:
給定的數獨序列只包含數字 1-9 和字符 ‘.’ 。
你可以假設給定的數獨只有唯一解。
給定數獨永遠是 9x9 形式的。
分析
此題相比上一題難度稍微大一些,是一個八皇后問題的變種,對于上一題我想我們已經知道怎么判斷這個是否滿足規則——使用三個boolean數組判斷。
但是,這一題有難度的就是需要我們手動放數據進去,手動去試探,并且每一步放置之后對后面都有影響。我們該如何思考這種問題呢?
dfs回溯,八皇后問題其實就是典型的回溯過程,而這種二維的回溯需要考慮一些問題,我們對于每一行每一行考慮。 每一行已經預有一些數據事先標記,在從開始試探放值,滿足條件后向下遞歸試探。一直到結束如果都滿足那么就可以結束返回數組值。
對于八皇后問題后面還會出一篇細講,這里的話有兩點需要注意的在這里提一下:
- 用二維兩個參數進行遞歸回溯判斷起來誰加誰減比較麻煩,所以我們用一個參數index用它來計算橫縱坐標進行轉換,這樣就減少二維遞歸的一些麻煩。
- 回溯是一個來回的過程,在回來的過程正常情況需要將數據改回去,但是如果已經知道結果就沒必要再該回去可以直接停止放置回溯造成值的修改(這里我用了一個isfinish的boolean類型進行判斷)。
具體ac代碼為:
boolean isfinish=false; boolean hang[][]=new boolean[9][10];//第一個是 9個坑,第二個是數字位置 boolean lie[][]=new boolean[9][10]; boolean fangge[][]=new boolean[9][10]; public void solveSudoku(char[][] board) {//首先遍歷一遍 將已有元素的行列信息提前做處理for(int i=0;i<board.length;i++){for(int j=0;j<board[0].length;j++){if(board[i][j]=='.') {continue;}int k=board[i][j]-'0'; hang[i][k]=true;lie[j][k]=true;fangge[(i/3)*3+j/3][k]=true;}} dfs(0,board); } private void dfs( int index, char[][] board) {if(isfinish) return;//已有結果不需要再計算if(index==81) {//到達最后一個前面都滿足條件說明可以停止了isfinish=true;return;}int i=index/9;//行int j=index%9;//列if(board[i][j]!='.')//已經有數字{dfs( index+1, board);}else {//此處需要補充數字for(int k=1;k<10;k++){ //如果不滿足直接跳過if(hang[i][k]||lie[j][k]||fangge[(i/3)*3+j/3][k]) {continue;}//滿足臨時試探修改 進行回溯board[i][j]=(char) (k+'0'); hang[i][k]=true;lie[j][k]=true;fangge[(i/3)*3+j/3][k]=true;//遞歸回溯dfs( index+1, board);//遞歸完成后需要復原,如果結束了不需要復原直接停止if(isfinish)return;board[i][j]='.'; hang[i][k]=false;lie[j][k]=false;fangge[(i/3)*3+j/3][k]=false;}} }結語
好啦,本次打卡結束,對于八皇后問題是一個經典的回溯遞歸問題,不久就會出一篇相關內容問題的具體分析,敬請來公眾號bigsai分享。如果想加入打卡還請加筆者公眾號bigsai 回復進群。一起打卡,回復bigsai獲取5G的pdf學習資源。
別忘了下方一鍵三聯哦!
總結
以上是生活随笔為你收集整理的LeetCode 36有效的数独37解数独(八皇后问题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode (二分小专题)33搜索
- 下一篇: LeetCode 38外观数列39组合总