题目链接:
https://leetcode-cn.com/problems/sudoku-solver/
难度:困难
37. 解数独
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
Note:
给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
这题有点难 对我来说。。。。 没做出来
看了下题解 勉强写了个递归(没有任何优化的 这应该是最差的做法了)
class Solution {
public:
bool line[9][9];
bool column[9][9];
bool block[3][3][9];
bool valid;
vector<pair<int,int>> spaces;
void dfs(vector<vector<char>>& board,int pos){
if(spaces.size()==pos){
valid=true;
return;
}
auto [i, j] = spaces[pos];
for(int digit=0;digit<9&&!valid;++digit){
if(!line[i][digit]&&!column[j][digit]&&!block[i/3][j/3][digit]){
line[i][digit]=true;
column[j][digit]=true;
block[i/3][j/3][digit]=true;
board[i][j]=digit+'0'+1;
dfs(board,pos+1);
line[i][digit]=false;
column[j][digit]=false;
block[i/3][j/3][digit]=false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line, false, sizeof(line));
memset(column, false, sizeof(column));
memset(block, false, sizeof(block));
valid = false;
for(int i=0;i<9;++i){
for(int j=0;j<9;++j){
if(board[i][j]=='.'){
spaces.emplace_back(i,j);
}else{
int digit=board[i][j]-'0'-1;
line[i][digit]=true;
column[j][digit]=true;
block[i/3][j/3][digit]=true;
}
}
}
dfs(board,0);
}
};
另一种方法 也是看的题解(非官方) 一位大佬的 做个标记大佬的解答 学到了 bitset (第一次接触)这种骚操作
按照大佬的思路来的 大佬np啊。。。 我感觉我下次碰到可能还不会。。。。。
class Solution {
public:
vector<bitset<9>> rows;
vector<bitset<9>> cols;
vector<vector<bitset<9>>> cells;
void solveSudoku(vector<vector<char>>& board){
rows = vector<bitset<9>>(9, bitset<9>());
cols = vector<bitset<9>>(9, bitset<9>());
cells = vector<vector<bitset<9>>>(3, vector<bitset<9>>(3, bitset<9>()));
int cnt = 0;
// 初始化rows cols cells
// cnt共有多少个空位
for (int i=0; i<board.size();i++){
for (int j=0; j<board[i].size();j++){
cnt+=(board[i][j]=='.');
if(board[i][j]=='.'){
continue;
}
int n=board[i][j]-'1';
rows[i]|=(1 << n);
cols[j]|=(1 << n);
cells[i/3][j/3]|=(1<<n);
}
}
dfs(board, cnt);
}
bool dfs(vector<vector<char>>& board, int cnt){
if(cnt==0){
return true;
}
auto next=getnext(board);
// 找出可填的数字 位=1时 对应的
auto bits=getPossibleStatus(next[0], next[1]);
if(bits.count()==0){
return false;
}
for(int i=0;i<bits.size();++i){
if(!bits.test(i)){
continue;
}
fillNum(next[0],next[1],i,true);
board[next[0]][next[1]] = i+'1';
if(dfs(board,cnt-1)){
return true;
}
fillNum(next[0],next[1],i,false);
board[next[0]][next[1]]='.';
}
return false;
}
// 找到限制条件最大的位置(可选数字最少)
vector<int> getnext(vector<vector<char>>& board){
vector<int> ret;
int mincnt=10;
for(int i=0;i<board.size();++i){
for(int j=0;j<board[i].size();++j){
if(board[i][j]!='.'){
continue;
}
auto cur=getPossibleStatus(i,j);
if(cur.count()>mincnt){
continue;
}
ret={i,j};
mincnt=cur.count();
}
}
return ret;
}
// 主要是判断限制条件的多少 越多,可能放的数字的个数越少
bitset<9> getPossibleStatus(int x,int y){
return ~(rows[x]|cols[y]|cells[x/3][y/3]);
}
// 更新数组
void fillNum(int x,int y,int n,bool fillFlag){
rows[x][n]=fillFlag?1:0;
cols[y][n]=fillFlag?1:0;
cells[x/3][y/3][n]=fillFlag?1:0;
}
};