【两次过】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;
    }
};

如果还是不能理解上面九宫格的下标算法,可以直接重新遍历即可,如下:

public class Solution {
    /**
     * @param board: the board
     * @return: whether the Sudoku is valid
     */
    public boolean isValidSudoku(char[][] board) {
        // write your code here
        if(board == null || board.length == 0 || board[0].length == 0)
            return true;
        
        int row = board.length;
        int col = board[0].length;
        
        //检查横排
        for(int i=0; i<row; i++){
            Set<Character> set = new HashSet<>();
            for(int j=0; j<col; j++){
                if(board[i][j] == '.')
                    continue;
                    
                if(set.contains(board[i][j]))
                    return false;
                else
                    set.add(board[i][j]);
            }
        }
        
        //检查竖排
        for(int j=0; j<col; j++){
            Set<Character> set = new HashSet<>();
            for(int i=0; i<row; i++){
                if(board[i][j] == '.')
                    continue;
                    
                if(set.contains(board[i][j]))
                    return false;
                else
                    set.add(board[i][j]);
            }
        }
        
        //检查3*3
        for(int i=0; i<row; i=i+3){
            
            for(int j=0; j<col; j=j+3){
                Set<Character> set = new HashSet<>();
                
                for(int m=i; m<row && m<i+3; m++){
                    for(int n=j; n<col && n <j+3; n++){
                        if(board[m][n] == '.')
                            continue;
                            
                        if(set.contains(board[m][n]))
                            return false;
                        else
                            set.add(board[m][n]);
                    }
                }
            }
        }
        
        return true;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值