这道题是补的前几天的题,是我在写LeetCode79单词搜索的时候错过的【社团出去聚餐了quq】
这道题又零零散散写了三天。
一眼就能看出来是回溯,但是具体要怎么写一时间我还想不出来,感觉限制条件太多,比N皇后还要复杂。
之后看了一眼题解,维护三个bool数组col[9][10], row[9][10], block[3][3][10]
。col[i][j]
表示j这个数字在第i行用没用过。之后按行来遍历回溯【按列或者块都是可以的】。思想是非常简单直白的。
class Solution {
public:
bool huiSu(vector<vector<char>> &board, bool row[][10], bool col[][10], bool block[][3][10],int r, int c)
{
//if (r == 8 && c == 8) return true;
while (board[r][c] != '.')
{
if (c == 8)
{
if (r != 8) r++;
else return true;
c = 0;
}
else c++;
}
for (int i = 1; i <= 9; i++)
{
if (row[r][i] == false && col[c][i] == false && block[r / 3][c / 3][i] == false)
{
row[r][i] = true;
col[c][i] = true;
block[r / 3][c / 3][i] = true;
board[r][c] = '0' + i;
if (c != 8)
{
if (huiSu(board, row, col, block, r, c + 1))
{
return true;
}
}
else if (r != 8)
{
if (huiSu(board, row, col, block, r + 1, 0))
{
return true;
}
}
else
{
if (huiSu(board, row, col, block, 8, 8))
{
return true;
}
}
row[r][i] = false;
col[c][i] = false;
block[r / 3][c / 3][i] = false;
board[r][c] = '.';
}
}
return false;
}
void solveSudoku(vector<vector<char>>& board) {
bool row[9][10], col[9][10], block[3][3][10];
memset(row, false, sizeof(row));
memset(col, false, sizeof(col));
memset(block, false, sizeof(block));
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (board[i][j] != '.')
{
row[i][board[i][j] - '0'] = true;
col[j][board[i][j] - '0'] = true;
block[i / 3][j / 3][board[i][j] - '0'] = true;
}
}
}
huiSu(board, row, col, block, 0, 0);
}
};
但是实现的时候还是遇到了问题TvT
1、可以看到我的终止条件写的非常啰嗦冗余,而且最后的最后发现if (r == 8 && c == 8) return true;
写在最前面是完全错误的,因为这个时候你还没有给最右下角那个格子board[8][8]赋值。
2、判断->赋值->递归->取消赋值 是回溯的基本套路,以前我写的时候会先赋值再判断,是行不通的【这里我还没有想得很明白到底是为什么】
3、回溯的那个函数一开始我写的是void型,后来看了别人的代码发现要写成bool型,好像这个也是回溯的基本套路?对,这是必须的,需要判断它有没有成功。
很好写的一道题,就是我太菜太菜了,不过跟着LeetCode的每日一题做了好多道回溯,现在有些掌握了qwq