驗證數獨棋盤

原題

  Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
  The Sudoku board could be partially filled, where empty cells are filled with the character '.'.
  這裏寫圖片描述
  A partially filled sudoku which is valid.
  Note:
  A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.算法

題目大意

  驗證一個數獨棋盤是否合法,數獨棋盤的驗證規則見連接對應的頁面。
  數獨棋盤是部分填滿的,空的位置使用點來代替。
  注意:合法的棋盤不必定要求的可解的,只要填充的數字知足要求就能夠。數組

解題思路

  先對行進行檢查,再對列進行檢查,最後檢查3*3的方格。spa

代碼實現

算法實現類.net

public class Solution {
    public boolean isValidSudoku(char[][] board) {
        // .的ASCII值是46,0的ASCII值是48,/的ASCII值是47
        int number = board[0].length;
        int[] record = new int[10 + 2]; //保存.到9的值,保存數據的位置在[2, 10]
        boolean isValid;
        reset(record);

        // 對行進行檢查
        for (int i = 0; i < number; i++) {
            for (int j = 0; j < number; j++) {
                record[board[i][j] - '.']++;
            }

            if (!check(record)) { // 如是檢查失敗
                return false;
            } else { // 檢查成功重置棋盤
                reset(record);
            }
        }

        // 對列進行檢查
        for (int i = 0; i < number; i++) {
            for (int j = 0; j < number; j++) {
                record[board[j][i] - '.']++;
            }

            if (!check(record)) { // 如是檢查失敗
                return false;
            } else { // 檢查成功重置棋盤
                reset(record);
            }
        }

        // 檢查3*3方塊
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {

                for (int k = i * 3; k < (i + 1) * 3; k++) {
                    for (int l = j * 3; l < (j + 1) * 3; l++) {
                        record[board[k][l]- '.']++;
                    }
                }

                if (!check(record)) { // 如是檢查失敗
                    return false;
                } else { // 檢查成功重置棋盤
                    reset(record);
                }
            }
        }
        return true;
    }

    private void reset(int[] a) {
        for (int i = 0; i < a.length; i++) {
            a[i] = 0;
        }


    }

    /**
     * 檢查棋盤一行,一列,或者3*3的方格是否合法,若是1-9中的數字個數大於1就不合法
     *
     * @param a 驗證數字
     * @return 返回結果
     */
    private boolean check(int[] a) {
        for (int i = 2; i < a.length; i++) {
            if (a[i] > 1) {
                return false;
            }
        }
        return true;
    }
}

數獨問題描述code

 

sudoku_1

標準的數獨遊戲是在一個 9 X 9 的棋盤上填寫 1 – 9 這 9 個數字,規則是這樣的:遞歸

  • 棋盤分紅上圖所示的 9 個區域(不一樣顏色作背景標出,每一個區域是 3 X 3 的子棋盤),在每一個子棋盤中填充 1 – 9 且不容許重複 ,下面簡稱塊重複
  • 每一行不準有重複值 ,下面簡稱行重複
  • 每一列不準有重複值 ,下面簡稱列重複

如上紅色框出的子區域中的亮黃色格子只能填 8。遊戲

 

 

解決思路一描述:圖片

1.使用二維數組表示數獨,不肯定的數使用0填充。get

2.從位置(0,0)開始遍歷二維數組。it

3.跳過已肯定的數字,直到找到第一個不肯定的數(即數值0)。若是找不到不肯定的數字,則表示數獨已填充完成。

4.根據當前數值0的位置,排除到同行、同列、同一個小宮格中已經出現的數字,獲得當前位置全部容許填充的數字。

5.若是不存在容許填充的數字,則當前數獨無解。

6.嘗試填充每個容許的數字,並遞歸填充下一個不肯定的數字。

7.若是遞歸填充成功,返回成功。

8.若是遞歸填充失敗,回退步驟6中填充的數字,並跳轉到6繼續嘗試下一個容許的數字。

 

相關代碼後續補充。

 

缺點:數獨中每個未肯定的值都須要遞歸窮舉,最大的遞歸層級等於未肯定值的數目。

改進方式:每填充一個值,在遞歸填充以前,動態計算每一個待填充值的候選數字,刪除再也不符合規則的候選數字。若是有位置的候選數字爲空,則數獨無解。若是有位置的候選數字只有惟一一個,則直接填充該數字。經過上述兩種方式能夠有效減小遞歸的層次。

相關文章
相關標籤/搜索