编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。
空白格用 '.'
表示。
一个数独。
答案被标成红色。
Note:
- 给定的数独序列只包含数字
1-9
和字符'.'
。 - 你可以假设给定的数独只有唯一解。
- 给定数独永远是
9x9
形式的。
思路:这题目用dfs来做,81个小格一共构成了81层,每一层有9个分支,分别取1-9之间的数。
方法1:采用哈希表的方法,要注意以下几点:
1、一开始要对原始棋盘上的数字进行标记,采用original函数。
2、dfs之前修改棋盘和use上的数字,dfs之后记得恢复棋盘和use上的数字。
class Solution { public: int use1[9][9] = {0}, use2[9][9] = {0}, use3[9][9] = {0}; void original(vector<vector<char>>& board) {//对棋盘上的原始数据进行标记 for (int i = 0; i < 9; ++i){ for (int j = 0; j < 9; ++j){ char x = board[i][j]; if (x == '.') continue; int aa = int(x - '0' - 1); int k = (i / 3) * 3 + j / 3;//注意box的i,j坐标要和第几个box,也就是use3中的哪一行对应好 use1[i][aa] = use2[j][aa] = use3[k][aa] = 1; } } } bool isValidSudoku(vector<vector<char>>& board, int i, int j, char c) {//每次验证当前棋盘上的数字是否是有效的 int aa = int(c - '0' - 1); int k = (i / 3) * 3 + j / 3;//注意box的i,j坐标要和第几个box,也就是use3中的哪一行对应好 if (use1[i][aa] || use2[j][aa] || use3[k][aa]) return false; use1[i][aa] = use2[j][aa] = use3[k][aa] = 1; //递归前修改 return true; } bool dfs(int i, int j, vector<vector<char>>& board){//深搜 if (i == 8 && j == 9) return true; if (j == 9){ ++i; j = 0; } if (board[i][j] != '.') return dfs(i, j + 1, board);//直接跳到下一层 else{ for (char c = '1'; c <= '9'; ++c){ if (isValidSudoku(board, i, j, c)){ board[i][j] = c; //递归前修改 if (dfs(i, j + 1, board)) return true; board[i][j] = '.'; //递归后恢复 int aa = int(c - '0' - 1); int k = (i / 3) * 3 + j / 3; use1[i][aa] = use2[j][aa] = use3[k][aa] = 0; } } return false; } } void solveSudoku(vector<vector<char>>& board) { isValidSudoku(board); dfs(0, 0, board); } };
方法2:不用哈希表,直接暴力:
class Solution { public: bool isValidSudoku(vector<vector<char>>& board, int i, int j, char c) {//暴力判断是否有效 for (int k = 0; k < 9; ++k){ if (board[i][k] == c) return false; if (board[k][j] == c) return false; if(board[(i / 3) * 3 + k/3][(j/3)*3+k%3]==c) return false; } return true; } bool dfs(vector<vector<char>>& board){ int i = 0, j = 0; for (i = 0; i < 9; ++i){ for (j = 0; j < 9; ++j){ if (board[i][j] == '.') break; } if (board[i][j] == '.') break; }//找到第一个'.' if (i == 9) return true;//说明棋盘填满了 for (char c = '1'; c <= '9'; ++c){ if (isValidSudoku(board, i, j, c)){ board[i][j] = c; //递归前修改 if (dfs(board)) return true; board[i][j] = '.'; //递归后恢复 } } return false; } void solveSudoku(vector<vector<char>>& board) { dfs(board); } };