我正在尝试进行在线Sudoku c ++测试问题。
我需要确定9x9数独板是否有效。仅需根据以下规则验证填充的单元格(某些单元格带有“。”以表示未填写):
对于我的解决方案,我遍历每行,每一列和每个子框网格。将这些数字添加到地图。并检查该地图是否重复。
我很确定我已经解决了标准1
和2
,但是我在想像如何遍历子框3x3网格时遇到了麻烦。因此,我改编了some code found here,说实话,我仍然无法完全解决问题。我认为这可能是造成问题的原因。
我该如何解决标准3?
示例输入,正确答案应返回False,但我的代码返回True:
[
[".",".","4",".",".",".","6","3","."],
[".",".",".",".",".",".",".",".","."],
["5",".",".",".",".",".",".","9","."],
[".",".",".","5","6",".",".",".","."],
["4",".","3",".",".",".",".",".","1"],
[".",".",".","7",".",".",".",".","."],
[".",".",".","5",".",".",".",".","."],
[".",".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".",".","."]
]
我(破)的解决方案:
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
//Iterate over each row
for (int x = 0; x < 9; x++) {
//Add row numbers to map
map<char, int> row_nums {};
for (int i = 0; i < 9; i++) {
if (board[x][i] != '.') {
row_nums[board[x][i]]++;
}
}
//Return false if duplicates found in row map
for (auto it = row_nums.begin(); it != row_nums.end(); ++it) {
if (it->second > 1) {
return false;
}
}
}
//Iterate over columns
for (int i = 0; i < 9; i++) {
//Add column numbers to map
map<char, int> col_nums {};
for (int y = 0; y < 9; y++) {
if (board[i][y] != '.') {
col_nums[board[i][y]]++;
}
}
//Return false if duplicates found in column map
for (auto it = col_nums.begin(); it != col_nums.end(); it++) {
if (it->second > 1) {
return false;
}
}
}
//Iterate over the 3x3 sub-boxes and add numbers to a map
//I think this is where I am stuck
for (int x = 0; x < 9; x++) {
for (int y = 0; y < 9; y++) {
map<char, int> box_nums {};
for (int bx = (x/3)*3; bx < (x/3)*3 + 3; bx++) {
for (int by = (y/3)*3; by < (y/3)*3 + 3; by++) {
if (board[bx][by] != '.') {
box_nums[board[bx][by]]++;
}
}
}
//Return false if duplicates found in column map
for (auto it = box_nums.begin(); it != box_nums.end(); it++) {
if (it->second > 1) {
return false;
}
}
}
}
//Else return true
return true;
}
};
答案 0 :(得分:2)
您共享的示例是有效的Sudoku w.r.t子框。第4列中有一个问题,其中有两个5
。必须更改列检查中的逻辑,以遍历每一行以保持列固定。
//Iterate over columns
for (int i = 0; i < 9; i++) {
//Add column numbers to map
map<char, int> col_nums {};
for (int y = 0; y < 9; y++) {
if (board[y][i] != '.') {
col_nums[board[y][i]]++;
}
}
//Return false if duplicates found in column map
for (auto it = col_nums.begin(); it != col_nums.end(); it++) {
if (it->second > 1) {
return false;
}
}
}
这应该可以解决您的问题。
不确定子框的问题,但这是另一种无需进行(bx/3)*3
等操作即可获取子框的方法
for (int x = 0; x < 9; x+=3) {
for (int y = 0; y < 9; y+=3) {
map<char, int> box_nums{};
for (int bx = x; bx < x + 3; bx++) {
for (int by = y; by < y + 3; by++) {
if (board[bx][by] != '.') {
box_nums[board[bx][by]]++;
}
}
}
//Return false if duplicates found in column map
for (auto it = box_nums.begin(); it != box_nums.end(); it++) {
if (it->second > 1) {
return false;
}
}
}
}
答案 1 :(得分:2)
首先,您不需要std::map
,并使用第二个循环来验证是否有大于1的计数,只需使用std::set
,并且如果insert操作返回false则意味着找到了重复项。其次,您只能拥有3个std::set
数组,并一次遍历所有行和列,然后为每个项目找到合适的std::set
:
const size_t size = 9;
using cset = std::set<char>;
using sets = std::array<cset,size>;
sets columns, rows, squares;
for( size_t i = 0; i < size; ++i ) {
for( size_t j = 0; j < size; ++j ) {
char n = board[i][j];
if( not checkSet( columns[i], n ) ) return false;
if( not checkSet( rows[j], n ) ) return false;
if( not checkSet( squares[i/3 + j/3*3], n ) ) return false;
}
}
return true;
其中checkSet()
可以这样简单:
bool checkSet( cset &s, char n )
{
return s.insert( n ).second;
}
注意:如果您关心效率,则应使用std::array<bool,size>
而不是std::set
,将字符转换为数字0-8并将其用作该数组中的索引。