您的位置:首页 > 其它

每天一道LeetCode-----数独盘求解

2017-11-05 14:51 369 查看

Valid Sudoku

原题链接Valid Sudoku



判断给定的数独盘是否有效,数独盘中可能有空位置。

简述一下数独的规则,参考连接Sudoku Puzzles - The Rules.

每一行,数字1-9只能出现一次

每一列,数字1-9只能出现一次

每个3 * 3方格中,数字1-9只能出现一次。这里3 * 3方格只包括9个,即图片中加粗黑线分开的9个方格

其实就是每个点只能存在1-9这九个数字中的一个,满足每一行,每一列,每个3 * 3方格不能出现重复的数字

判断一个数独盘是否有效,只需要判断是否满足上述三个规则即可。另外,如果给出的数独盘像图片那样有些地方没有填充数字,也没有关系。只需要判断有数字的部分就好,比如说第一行只有5, 3, 7,那么可以判断第一行没有出现重复的数字,是满足规则一的。

肯定需要全部遍历一遍,每遍历到一个位置,就判断它所在的行,所在的列,所在的3 * 3方格是否已经存在同样的数字了,如果存在,返回false,否则,将这个数字添加到行,列,3 * 3方格的记录中。

所以需要分别记录每一行,每一列,每一个3 * 3方格都有那些数字出现过,其实就是3个二维数组

记录每一行都出现了哪些数字,
vector<vector<int>> rows(9, vector<int>(10, 0));


记录每一列都出现了哪些数字,
vector<vector<int>> columns(9, vector<int>(10, 0));


记录每个3 * 3方格都出现了哪些数字,
vector<vector<int>> boxes(9, vector<int>(10, 0));


对于3 * 3方格,这里用
vector<vector<int>> boxes(9, vector<int>(10, 0));
形式表示,意思是这个数独盘是由9个3 * 3方格,编号从0到8。对于某个位置(row, column)而言,它所在的3 * 3方格编号为
row / 3 * 3 + column / 3


表示方法,假设当前位置为(i, j),数字为n

rows[i]
表示第i行出现数字n的个数,不是1就是0

columns[j]
表示第j列出现数字n的个数,不是1就是0

boxes[i / 3 * 3 + j / 3]
表示当前位置所在的方格出现数字n的个数,不是1就是0

代码如下

class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector<vector<int>> rows(9, vector<int>(10, 0));
vector<vector<int>> columns(9, vector<int>(10, 0));
vector<vector<int>> boxes(9, vector<int>(10, 0));

for(int i = 0; i < board.size(); ++i)
{
for(int j = 0; j < board[i].size(); ++j)
{
if(board[i][j] == '.')
continue;

int n = board[i][j] - '0';
/* 如果之前有出现过(不为0),就说明数独盘无效 */
if(rows[i]
|| columns[j]
|| boxes[i / 3 * 3 + j / 3]
)
return false;
/* 否则,更新每一行,每一列,所在方格的内容 */
else
rows[i]
= columns[j]
= boxes[i / 3 * 3 + j / 3]
= 1;
}
}

return true;
}

};


扩展

Sudoku Solver

原题链接Sudoku Solver



给定一个有效的数独盘,解出结果。

解一个数独盘就是要求把所有的空格都填上数字,要求仍然是满足上述三个规则,即

每一行,数字1-9只能出现一次

每一列,数字1-9只能出现一次

每个3 * 3方格中,数字1-9只能出现一次。这里3 * 3方格只包括9个,即图片中加粗黑线分开的9个方格

对于某个空格,它所能填充的数字需要满足

在所在行没有出现过的

在所在行没有出现过的

在所在3 * 3方格没有出现过的

所以在上面的问题中,已经把每一行,每一列,每个3 * 3方格出现的数字都找出了,接下来就是深度优先(dfs)把每个空格填上数字即可,当然填充的数字需要满足上面的要求。

如果填充到某个位置发现没有可选的数字了,就说明之前的某个位置选择错了,就回退到之前的位置,选择另一个满足上述要求的数字

代码如下

class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
vector<vector<int>> rows(9, vector<int>(10, 0));
vector<vector<int>> columns(9, vector<int>(10, 0));
vector<vector<int>> boxes(9, vector<int>(10, 0));

/* 计算每一行,每一列,每个3 * 3方格中每个数字是否出现 */
for(int i = 0; i < board.size(); ++i)
{
for(int j = 0; j < board[i].size(); ++j)
{
if(board[i][j] == '.')
continue;

int n = board[i][j] - '0';
rows[i]
= columns[j]
= boxes[i / 3 * 3 + j / 3]
= 1;
}
}

bool done = false;
dfs(board, rows, columns, boxes, 0, 0, done);
}

private:
void dfs(vector<vector<char>>& board, vector<vector<int>>& rows,
vector<vector<int>>& columns, vector<vector<int>>& boxes,
int row, int column, bool& done)
{
/* 填充完成 */
if(row >= board.size())
{
done = true;
return;
}
/* 当前某一行的末尾,换到下一行 */
else if(column >= board[row].size())
{
dfs(board, rows, columns, boxes, row + 1, 0, done);
}
/* 如果有数字,则不需要填充,继续下一个 */
else if(board[row][column] != '.')
{
dfs(board, rows, columns, boxes, row, column + 1, done);
}
else
{
for(int n = 1; n <= 9; ++n)
{
/* 如果数字出现过,就不能填充到当前位置 */
if(rows[row]
|| columns[column]
|| boxes[row / 3 * 3 + column / 3]
)
continue;

/* 将填充的数字记录下来 */
rows[row]
= columns[column]
= boxes[row / 3 * 3 + column / 3]
= 1;
board[row][column] = n + '0';
/* 递归填充下一个空格 */
dfs(board, rows, columns, boxes, row, column + 1, done);
/* 如果完成,就退出 */
if(done)
{
return;
}
/* 否则,回到填充之前的状态,重新找数字 */
else
{
rows[row]
= columns[column]
= boxes[row / 3 * 3 + column / 3]
= 0;
board[row][column] = '.';
}
}
}
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode
相关文章推荐