LeetCode - 36. Valid Sudoku
這道題就是根據已給出的陣列中的數來判斷該陣列是不是Valid的,也就是行,列,九宮格中都不能出現相同的數字。
A partially filled sudoku which is valid. 上邊的這個陣列就是valid的。
The Sudoku board could be partially filled, where empty cells are filled with the character '.'
.
用 '.' 表示空的位置,空的位置跳過就好了。
Input: [ ["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"] ] Output: true Input: [ ["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"] ] Output: false Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid. 一列裡邊有兩個8,第一個九宮格里邊也有兩個8,就不是valid。
解:
這道題比較簡單,因為只需要判斷從給出的數字中有沒有出現行,列,或者九宮格中重複的數字即可,這個陣列有沒有解這道題並不關心。
很直接的想法就是分別看每行,每列,每個九宮格中有沒有出現過重複的數字。用unordered_set很容易實現。
bool isValidSudoku(vector<vector<char>>& board) { unordered_set<char> setB; // 判斷行 for(int i = 0; i < 9; i++){ setB.clear(); for(int j = 0; j < 9; j++){ if(board[i][j] != '.') { if(setB.find(board[i][j]) != setB.end()) return false; else setB.insert(board[i][j]); } } } // 判斷列 for(int i = 0; i < 9; i++){ setB.clear(); for(int j = 0; j < 9; j++){ if(board[j][i] != '.') { if(setB.find(board[j][i]) != setB.end()) return false; else setB.insert(board[j][i]); } } } // 判斷九宮格 for(int i = 0; i < 9; i += 3){ for(int j = 0; j < 9; j += 3){ setB.clear(); for(int x = 0; x < 3; x++){ for(int y = 0; y < 3; y++){ if(board[i + x][j + y] != '.') { if(setB.find(board[i + x][j + y]) != setB.end()) return false; else setB.insert(board[i + x][j + y]); } } } } } return true; }
所有的演算法都應該是這種思想,判斷三種情況下有沒有重複的,有的話直接返回false,全判斷玩還沒有錯就返回true。但是有更簡便的寫法,就是用三個9 * 9陣列表示行,列,九宮格中的數字有沒有出現過,比如row_appear[1][2] = 1,就表示,第1行中,2出現過了,如果等於0就是沒出現過。所以在初始化時需要將三個陣列全初始化為0,表示遍歷board陣列之前,所有數都沒有出現過。程式碼如下:
bool isValidSudoku(vector<vector<char> > &board) { // 因為要初始化為0,所以直接就這麼寫了,否則不行 int row_appear[9][9] = {0}, col_appear[9][9] = {0}, box_appear[9][9] = {0}; for(int i = 0; i < board.size(); ++ i) for(int j = 0; j < board[i].size(); ++ j) if(board[i][j] != '.') { int num = board[i][j] - '0' - 1; // 因為行,列,九宮格的數都是 0 ~ 8 int k = i / 3 * 3 + j / 3; // 第幾個九宮格 if(row_appear[i][num] || col_appear[j][num] || box_appear[k][num]) return false; row_appear[i][num] = col_appear[j][num] = box_appear[k][num] = 1; } return true; }
每個陣列中的數只有1和0兩種可能,a[i][j] = 1(泛指三個陣列) 表示這個陣列中第 i 行出現過 j 這個數了:
1、如果是表示行的陣列,則表示board陣列中,第 i 行出現過了 j 這個數;
2、如果是表示列的陣列,則表示board陣列中,第 i 列出現過了 j 這個數;
3、如果是表示九宮格的陣列,則表示board陣列中,第 i 個九宮格中出現過了 j 這個數。
九宮格的順序按照程式碼中的寫法應該是下圖。