本文介绍两道与数独相关的题
第一题 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.
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.
这题的题意是给你一个二维向量,代表一个数独,其中的’.’代表空白,要求验证所给数独是否是合理的。注意一点,这里只要求验证合理性,而不需要判断是否有解,我之前是先做了下面的一道,把它拿过来是Wrong
这道题理解了这一点后思路就明确了:只要依次判断九行、九列以及九个九宫格是否有重复数字即可,代码如下:
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
bool res = true;
//分别代表每列每行和每个九宫格的数字
int cols[10] = { 0 }, rows[10] = { 0 }, cubes[10] = { 0 };
int nums[10] = { 0 };
for (int i = 0; i < 9; ++i)
{
memset(rows, 0, sizeof(rows));
memset(cols, 0, sizeof(cols));
for (int j = 0; j < 9; ++j)
{
//若一个数字在行或列中出现两次,则直接return false
int col = board[i][j], row = board[j][i];
if (col != '.')
{
cols[col - '0']++;
if (cols[col - '0'] > 1) return false;
}
if (row != '.')
{
rows[row - '0']++;
if (rows[row - '0'] > 1) return false;
}
}
}
for(int i = 0; i < 9; i += 3)
for (int j = 0; j < 9; j += 3)
{
memset(cubes, 0, sizeof(cubes));
for(int m = 0; m < 3; ++m)
for (int n = 0; n < 3; ++n)
{
int num = board[i + m][j + n];
if (num != '.')
{
cubes[num - '0']++;
if (cubes[num - '0'] > 1) return false;
}
}
}
return true;
}
};
当然,从我之前做ACM的角度,这道题非常不”严谨”… 特别对于Valid这个词的用法…有个测试用例是这样的:
其实我们一眼就看出来是“错”的,但根据我们的代码应该输出true,因此就像最开始说的,要区分“Valid”和有解
那么第二道就来了,求解数独 37. Sudoku Solver
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
1. Each of the digits 1-9 must occur exactly once in each row.
2. Each of the digits 1-9 must occur exactly once in each column.
3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character ‘.’.
题意同样给定一个二维向量,求解该数独。
我这里用的是DFS的解法,也就是先一条路走到黑,要是发现哪个节点已经无法填数字了,再回溯到上一轮重新填写。代码如下,解法都在注释中:
class Solution {
public:
void solveSudoku(vector<vector<char>>& board)
{
dfs(board, 0);
}
//len代表已经填好的位置数量
bool dfs(vector<vector<char>>& board, int len)
{
//len=81表示全部填好,直接返回true即可
if (len == 81) return true;
//自己构建一下会发现,len/9即行号,len%9为列号
int i = len / 9, j = len % 9;
if (board[i][j] != '.')
{
return dfs(board, len + 1);
}
//flag数组储存所有已经被使用过的数字
bool flag[10] = { false };
memset(flag, true, sizeof(flag));
//通过valid函数,将已经使用过的数字置false
valid(flag, board, i, j);
for (int l = 1; l < 10; ++l)
{
//只有1~9可以填,若flag为true,即表示可以使用
if (flag[l])
{
//直接赋值该数字,并进行下一轮遍历
board[i][j] = l + '0';
if (dfs(board, len + 1))
return true;
}
}
//若发现从1~9都不能成功,就说明前一轮或几轮中有错误的填写,需把当前位置重置'.',并返回到上一轮
board[i][j] = '.';
return false;
}
void valid(bool flag[], vector<vector<char>> board, int i, int j)
{
//判断第i行第j列的元素所在行列以及其所在的九宫格已经有哪些数字
for (int k = 0; k < 9; ++k)
{
if (board[i][k] != '.')
{
flag[board[i][k] - '0'] = false;
}
if (board[k][j] != '.')
{
flag[board[k][j] - '0'] = false;
}
}
i /= 3, j /= 3;
for(int k = 0; k < 3; ++k)
for (int m = 0; m < 3; ++m)
{
if (board[i * 3 + k][j * 3 + m] != '.')
{
flag[board[i * 3 + k][j * 3 + m] - '0'] = false;
}
}
}
};