leetcode 37.解数独
题干
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
题解
dfs+回溯算法
* 回溯算法的核心在于条件重新置false的语句的位置
* 第一遍写的时候语句A被我放在了位置B,这样写的结果是:一旦在填入数字进行后续的递归时遇到了不满足if条件的情况,就会将出现标记置false的情况,比如在一轮递归的for0-8时,
这个位置只能填8,写在外面就会导致把0-7的标记全部记false,这明显是错的。
* 将语句A放在位置A的原因是如果以这个数为起点的递归在后续出现了无答案的情况,会回到位置A使用下一个数进行第二轮递归(即回溯算法的本意),所以语句A的作用实际上是对错误答案的消除,
所以应该与数字一一对应
class Solution {
public:
bool line[9][9];
bool column[9][9];
bool block[9][9];
bool finish = false;
vector<pair<int,int>> space;
void dfs(vector<vector<char>>& board,int pos){
if(pos==space.size())
{
finish = true;
return;
}
auto [x,y] = space[pos];
for(int digit=0;digit<9 && !finish;digit++)
{
//cout<<x<<' '<<y<<' '<<digit<<endl;
if(line[x][digit]==false && column[y][digit]==false && block[x/3*3+y/3][digit]==false)
{
line[x][digit] = column[y][digit] = block[x/3*3+y/3][digit] = true;
board[x][y] = digit + '0' + 1;
dfs(board,pos+1);
line[x][digit] = column[y][digit] = block[x/3*3+y/3][digit] = false;//!!!!!!!!!!!!!!!!!!!!!!!!!!!就是这句语句,记为语句A,位置A
}
//board[x][y] = '.';
//原来语句A所在的位置,记为位置B
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line,false,sizeof(line));
memset(column,false,sizeof(column));
memset(block,false,sizeof(block));
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
if(board[i][j]!='.')
{
int num = board[i][j] - '1';//这里的num是实际数字-1,方便数组操作
int blockIndex = i / 3 * 3 + j / 3;
//cout<<blockIndex<<' ';
line[i][num] = column[j][num] = block[blockIndex][num] = true;
}
else
space.emplace_back(i,j);
}
}
dfs(board,0);
}
};
/*block
0 1 2
3 4 5
6 7 8
*/
一次改进:
* 仿照了上次组合问题用二进制保存状态的方法,把line column block变为一位数组,缩短了运行时间,
* 尼玛力扣的官方题解运行好快 ~表示按位取反
class Solution {
public:
int line[9];
int column[9];
int block[9];
bool finish = false;
vector<pair<int,int>> space;
void dfs(vector<vector<char>>& board,int pos){
if(pos==space.size())
{
finish = true;
return;
}
auto [x,y] = space[pos];
for(int digit=0;digit<9 && !finish;digit++)
{
//cout<<x<<' '<<y<<' '<<digit<<endl;
int mask = 1<<digit;
if((line[x]&mask)==0 && (column[y]&mask)==0 && (block[x/3*3+y/3]&mask)==0)
{
line[x] += mask;
column[y] += mask;
block[x/3*3+y/3] += mask;
board[x][y] = digit + '0' + 1;
dfs(board,pos+1);
line[x] -= mask;
column[y] -= mask;
block[x/3*3+y/3] -= mask;
}
//board[x][y] = '.';
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line,false,sizeof(line));
memset(column,false,sizeof(column));
memset(block,false,sizeof(block));
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
if(board[i][j]!='.')
{
int num = board[i][j] - '1';//这里的num是实际数字-1,方便数组操作
int blockIndex = i / 3 * 3 + j / 3;
//cout<<blockIndex<<' ';
line[i] += 1<<num;
column[j] += 1<<num;
block[blockIndex] += 1<<num;;
}
else
space.emplace_back(i,j);
}
}
dfs(board,0);
}
};
/*block
0 1 2
3 4 5
6 7 8
*/