1. 程式人生 > >【三次過】Lintcode 389. 判斷數獨是否合法

【三次過】Lintcode 389. 判斷數獨是否合法

請判定一個數獨是否有效。

該數獨可能只填充了部分數字,其中缺少的數字用 . 表示。

樣例

The following partially filed sudoku is valid.

解題思路:

驗證數獨是否有效,就三個要求:

1.數字1-9在每一行最多隻能出現一次

2.數字1-9在每一列最多隻能出現一次

3.數字1-9在每一個3*3九宮格內最多隻能出現一次

出現有次數的題目,一般採用雜湊表,所以我們只需要檢查每一行,每一列,每個九宮格中數字出現的次數即可,分別用三個雜湊表儲存。

難點在於表示第i個九宮格每個格點的座標。

觀察行號規律:

第0個九宮格:000111222; 第1個九宮格:000111222; 第2個九宮格:000111222;

第3個九宮格:333444555; 第4個九宮格:333444555; 第5個九宮格:333444555;

第6個九宮格:666777888; 第7個九宮格:666777888; 第8個九宮格:666777888;

可見對於每三個九宮格行號增3;對於單個九宮格,每三個格點行號增1。

因此第i個九宮格的第j個格點的行號可表示為i/3*3+j/3

觀察列號規律:

第0個九宮格:012012012; 第1個九宮格:345345345; 第2個九宮格:678678678;

第3個九宮格:012012012; 第4個九宮格:345345345; 第5個九宮格:678678678;

第6個九宮格:012012012; 第7個九宮格:345345345; 第8個九宮格:678678678;

可見對於下個九宮格列號增3,迴圈週期為3;對於單個九宮格,每個格點行號增1,週期也為3。

週期的數學表示就是取模運算mod。

因此第i個九宮格的第j個格點的列號可表示為i%3*3+j%3

class Solution {
public:
    /**
     * @param board: the board
     * @return: whether the Sudoku is valid
     */
    bool isValidSudoku(vector<vector<char>> &board)
    {
        // write your code here
        for(int i=0;i<board.size();i++)
        {
            unordered_map<char,int> m_row;
            unordered_map<char,int> m_col;
            unordered_map<char,int> m_san;
            
            for(int j=0;j<board[i].size();j++)
            {
                if(board[i][j] != '.' && ++m_row[board[i][j]] > 1)//檢查每一行的元素是否重複
                    return false;

                    
                if(board[j][i] != '.' && ++m_col[board[j][i]] > 1)//檢查每一列的元素是否重複
                    return false;
                    
                if(board[i/3*3+j/3][i%3*3+j%3] != '.' && 
                    ++m_san[board[i/3*3+j/3][i%3*3+j%3]] > 1)//檢查每個九宮格的元素是否重複
                    return false;
            }
        }
        
        return true;
    }
};

如果還是不能理解上面九宮格的下標演算法,可以直接重新遍歷即可,如下:

class Solution {
public:
    /**
     * @param board: the board
     * @return: whether the Sudoku is valid
     */
    bool isValidSudoku(vector<vector<char>> &board)
    {
        // write your code here
        for(int i=0;i<board.size();i++)
        {
            unordered_map<char,int> m_row;
            unordered_map<char,int> m_col;
            
            for(int j=0;j<board[i].size();j++)
            {
                if(board[i][j] != '.' && ++m_row[board[i][j]] > 1)//檢查每一行的元素是否重複
                    return false;

                    
                if(board[j][i] != '.' && ++m_col[board[j][i]] > 1)//檢查每一列的元素是否重複
                    return false;
            }
        }
        

        for(int i=0;i<board.size();i+=3)
        {
            for(int j=0;j<board[i].size();j+=3)
            {
                unordered_map<char,int> m_san;
                
                for(int row=i;row<i+3;row++)
                    for(int col=j;col<j+3;col++)
                        if(board[row][col] != '.' 
                        && ++m_san[board[row][col]] > 1)//檢查每個九宮格的元素是否重複
                            return false;
            }
        }
        
        return true;
    }
};