LeetCode--36. Valid Sudoku

一、问题描述

Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following .

rules :

  1. Each row must contain the digits 1-9 without repetition.
  2. Each column must contain the digits 1-9 without repetition.
  3. Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.

LeetCode--36. Valid Sudoku_第1张图片

The Sudoku board could be partially filled, where empty cells are filled with the character '.'.

Example 1:

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

Example 2:

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.

Note :

  • A Sudoku board (partially filled) could be valid but is not necessarily solvable.
  • Only the filled cells need to be validated according to the mentioned rules.
  • The given board contain only digits 1-9 and the character '.'.
  • The given board size is always 9x9.

二、解题思路

咋一看以为是解数独,会很复杂。读完题目后,发现只要求判断当前的棋盘上的数字是不是有效的,不需要考虑最终这个数独是不是可以解。所以相当于只需要判断当前这个已经存在的棋盘是否满足数独规则的要求。

数独的规则要求,每行,每列,以及每个3x3的子棋盘上,是否包括1-9这9个数字且不重复。现在考虑,肯定是需要把整个棋盘扫描一遍的,那么我们可以设置三个状态数组,来分别记录下以及扫描过的 行/列/子棋盘 中已经出现过的数,如果扫描到某 行/列/子棋盘 中有重复的元素前面已经出现过,直接返回false;若直到扫描结束,也为发现重复元素,说明棋盘有效,返回true。但是由于要记录每 行/列/子棋盘 的状态,需要声明三个较大的数组,所以对空间的消耗较高,应该还有更优化的解法。

评论区解题的大致思路都差不多,区别主要再求如何存储状态数组。有一种很优化的方法是利用位操作实现的,这种方法只使用一个short就存储了一行的状态,节省了很多空间,效率也得到了提升。

  1. 每行的状态初始化为0;
  2. 遇到一个数字num,就将1左移num位与状态数进行与操作,若结果不为0,说明有重复,返回false;否则,无重复,更新状态,即两数进行或操作。

参考:
C++ very simple and easy understand. using bit operation
My C++ code (O(n2) time and space)

三、代码

解法1

       
      
      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
       
      
      
      
class {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector< vector< bool>> rows( 9, vector< bool>( 9, false));
vector< vector< bool>> columns( 9, vector< bool>( 9, false));
vector< vector< bool>> sub_box( 9, vector< bool>( 9, false));
for( int i = 0; i < 9; i++)
{
for( int j = 0; j < 9; j++)
{
if(board[i][j] == '.') continue;
int sub_box_index = (i/ 3)* 3 + (j/ 3);
int num = board[i][j] - '1';
if(rows[i][num] || columns[j][num] || sub_box[sub_box_index][num])
return false;
rows[i][num] = columns[j][num] = sub_box[sub_box_index][num] = true;
}
}
return true;
}
};

利用位操作

       
      
      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
       
      
      
      
class {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector< short> col( 9, 0);
vector< short> block( 9, 0);
vector< short> row( 9, 0);
for ( int i = 0; i < 9; i++)
for ( int j = 0; j < 9; j++)
{
if (board[i][j] != '.')
{
int idx = 1 << (board[i][j] - '0');
if (row[i] & idx || col[j] & idx || block[i/ 3 * 3 + j / 3] & idx)
return false;
row[i] |= idx;
col[j] |= idx;
block[i/ 3 * 3 + j/ 3] |= idx;
}
}
return true;
}
};

解法3

       
      
      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
       
      
      
      
class {
public:
bool isValidSudoku(vector<vector<char> > &board) {
char existNum[ 10][ 10]={ 0};
int i,j;
for(i= 0; i< 9; i++)
{
for(j= 0; j< 9; j++)
{
if(board[i][j]!= '.')
{
if(existNum[i][board[i][j] - '0'] & 0x1) return false;
if(existNum[j][board[i][j] - '0'] & 0x2) return false; // check if the j-col already has such number, 2-LSB
if(existNum[(i/ 3) * 3 + j/ 3][board[i][j] - '0'] & 0x4) return false; // check if the k-subblock already has such number, 3-LSB
existNum[i][board[i][j] - '0'] ^= 0x1;
existNum[j][board[i][j] - '0'] ^= 0x2;
existNum[(i/ 3) * 3 + j/ 3][board[i][j] - '0'] ^= 0x4;
}
}
}
return true;
}
};

原文:大专栏  LeetCode--36. Valid Sudoku


你可能感兴趣的:(LeetCode--36. Valid Sudoku)