1. 程式人生 > 其它 >力扣 36.有效的數獨

力扣 36.有效的數獨

36. 有效的數獨

請你判斷一個 9 x 9 的數獨是否有效。只需要 根據以下規則 ,驗證已經填入的數字是否有效即可。

  1. 數字 1-9 在每一行只能出現一次。
  2. 數字 1-9 在每一列只能出現一次。
  3. 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。(請參考示例圖)

 

注意:

  • 一個有效的數獨(部分已被填充)不一定是可解的。
  • 只需要根據以上規則,驗證已經填入的數字是否有效即可。
  • 空白格用 '.' 表示。

 

示例 1:

輸入:board = 
[["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:

輸入:board = 
[["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 存在, 因此這個數獨是無效的。

官方

連結

方法一:一次遍歷
有效的數獨滿足以下三個條件:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int rows[9][9];
        int columns[9][9];
        int subboxes[3][3][9];
        
        memset(rows,0,sizeof(rows));
        memset(columns,0,sizeof(columns));
        memset(subboxes,0,sizeof(subboxes));
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char c = board[i][j];
                if (c != '.') {
                    int index = c - '0' - 1;
                    rows[i][index]++;
                    columns[j][index]++;
                    subboxes[i / 3][j / 3][index]++;
                    if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
};

大神思路

連結

與官方題解不一樣在

遍歷到每個數的時候,例如boar[i][j],我們判斷其是否滿足三個條件:

在第 i 個行中是否出現過
在第 j 個列中是否出現過
在第 j/3 + (i/3)*3個box中是否出現過.為什麼是j/3 + (i/3)*3呢?
關於從陣列下標到box序號的變換
 重述一遍問題:給定i和j,如何判定board[i][j]在第幾個box呢?
 顯然屬於第幾個box由i和j的組合唯一確定,例如board[2][2]一定是第0個box,board[4][7]一定是第5個box,可以畫出來看一下,但是規律在哪裡呢?
我們可以考慮一種簡單的情況: 一個3x9的矩陣,被分成3個3x3的box,如圖:


顯然每個數屬於哪個box就只取決於縱座標,縱座標為0/1/2的都屬於box[0],縱座標為3/4/5的都屬於box[1],縱座標為6/7/8的都屬於box[2].也就是j/3.
而對於9x9的矩陣,我們光根據j/3得到0/1/2還是不夠的,可能加上一個3的倍數,例如加0x3,表示本行的box,加1x3,表示在下一行的box,加2x3,表示在下兩行的box, 這裡的0/1/2怎麼來的?和j/3差不多同理,也就是i/3。

合併

利用大神處理subbox的思路 j/3 + (i/3)*3

優化一下subboxes[3][3][9]

 變成二維

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int rows[9][9];
        int columns[9][9];
        int subboxes[9][9];
        
        memset(rows,0,sizeof(rows));
        memset(columns,0,sizeof(columns));
        memset(subboxes,0,sizeof(subboxes));
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char c = board[i][j];
                if (c != '.') {
                    int index = c - '0' - 1;
                    rows[i][index]++;
                    columns[j][index]++;
                    subboxes[j/3 + (i/3)*3][index]++;
                    if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[j/3 + (i/3)*3][index] > 1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
};