1. 程式人生 > >LeetCode - 36. Valid Sudoku

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 這個數。

    九宮格的順序按照程式碼中的寫法應該是下圖。