Pre-hash数组 + component-DFS
前言
题目约束既是问题的出现,也是解决问题的钥匙。利用好问题条件和特性,拆解问题并优化解法。 通过解数独来完成困难题的拆解与题解优化。
一、解数独
归类:Pre-hash数组 + component-DFS类型的题。
二、hash为DFS赋能
1、Pre-hash数组 + component-DFS
public class SolveSudoku {
public void solveSudoku(char[][] board) {
int[][] row = new int[9][9];
int[][] col = new int[9][9];
int[][][] grid = new int[3][3][9];
setHash(board, row, col, grid);
dfs(board, row, col, grid, 0, 0);
}
private boolean dfs(char[][] board, int[][] row, int[][] col, int[][][] grid, int i, int j) {
int m = board.length, n = board[0].length;
if (i == m - 1 && j == n) return true;
if (j == n) {
j = 0;
i = i + 1;
}
boolean flag = false;
if (board[i][j] != '.') flag = dfs(board, row, col, grid, i, j + 1);
else {
for (int k = 0; k < 9; k++) {
if (row[i][k] == 0 && col[j][k] == 0 && grid[i / 3][j / 3][k] == 0) {
board[i][j] = (char) (k + 1 + '0');
row[i][k] = 1;
col[j][k] = 1;
grid[i / 3][j / 3][k] = 1;
flag = dfs(board, row, col, grid, i, j + 1);
if (flag) return true;
board[i][j] = '.';
row[i][k] = 0;
col[j][k] = 0;
grid[i / 3][j / 3][k] = 0;
}
}
}
return flag;
}
private void setHash(char[][] board, int[][] row, int[][] col, int[][][] grid) {
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] != '.') {
row[i][board[i][j] - '1']++;
col[j][board[i][j] - '1']++;
grid[i / 3][j / 3][board[i][j] - '1']++;
}
}
}
}
}
2、1-9二进制状态压缩
class SolveSudoku2 {
public void solveSudoku(char[][] board) {
int[] row = new int[9];
int[] col = new int[9];
int[][] grid = new int[3][3];
setHash(board, row, col, grid);
dfs(board, row, col, grid, 0, 0);
}
private boolean dfs(char[][] board, int[] row, int[] col, int[][] grid, int i, int j) {
int m = board.length, n = board[0].length;
if (i == m - 1 && j == n) return true;
if (j == n) {
j = 0;
i = i + 1;
}
boolean flag = false;
if (board[i][j] != '.') flag = dfs(board, row, col, grid, i, j + 1);
else {
for (int k = 0; k < 9; k++) {
int val = 1 << k + 1;
if ((row[i] & val) == 0 && (col[j] & val) == 0 && (grid[i / 3][j / 3] & val) == 0) {
board[i][j] = (char) (k + 1 + '0');
row[i] |= val;
col[j] |= val;
grid[i / 3][j / 3] |= val;
flag = dfs(board, row, col, grid, i, j + 1);
if (flag) return true;
board[i][j] = '.';
row[i] -= val;
col[j] -= val;
grid[i / 3][j / 3] -= val;
}
}
}
return flag;
}
private void setHash(char[][] board, int[] row, int[] col, int[][] grid) {
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] != '.') {
int val = 1 << board[i][j] - '0';
row[i] |= val;
col[j] |= val;
grid[i / 3][j / 3] |= val;
}
}
}
}
}
总结
1)利用问题的约束条件和目标来拆解问题。 2)利用问题的特性来完成题解的优化。 3)hash数组、DFS-递归回溯练习、二进制方式来状态压缩(新颖技巧)。
参考文献
[1] LeetCode 解数独 [2] LeetCode 解数独–官方题解–方法二–状态压缩
|