解数独。需要先做36题。做完36题,37题需要做的就是根据规则填充input。填充的规则是如果当前坐标上是一个点(.)的话,尝试放1-9之间的一个数字,放进去之后判断两件事,1是是否有效(这个数字在当前行/列/九宫格是否被放过了),2是放进去之后接着往下迭代处理剩下的部分的时候看看是否依然能解决完整个数独。所以这道题会牵涉到DFS回溯。
时间 - (9!)^9
空间O(1) - no extra space needed
Java实现
1 class Solution { 2 public void solveSudoku(char[][] board) { 3 if (board == null || board.length == 0) { 4 return; 5 } 6 solve(board); 7 } 8 9 public boolean solve(char[][] board) { 10 for (int i = 0; i < board.length; i++) { 11 for (int j = 0; j < board[0].length; j++) { 12 if (board[i][j] == '.') { 13 for (char c = '1'; c <= '9'; c++) { 14 if (isValid(board, i, j, c)) { 15 board[i][j] = c; 16 if (solve(board)) { 17 return true; 18 } else { 19 board[i][j] = '.'; 20 } 21 } 22 } 23 return false; 24 } 25 } 26 } 27 return true; 28 } 29 30 public boolean isValid(char[][] board, int row, int col, char c) { 31 for (int i = 0; i < 9; i++) { 32 if (board[i][col] == c) { 33 return false; 34 } 35 if (board[row][i] == c) { 36 return false; 37 } 38 if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] != '.' 39 && board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) { 40 return false; 41 } 42 } 43 return true; 44 } 45 }
2021年4月更新
我这里再提供一种更好理解的做法。首先我们还是创建三个boolean的二维数组记录已经存在的数字,然后我们需要一个helper函数去做backtracking,模拟完其他还不存在的数字。helper函数的退出条件是模拟到了最右下角的坐标;在没有模拟完毕之前,对于每个还没有填充过数字的坐标,我们都尝试去填充从1到9的每一个数字。
Java实现
1 class Solution { 2 public void solveSudoku(char[][] board) { 3 // 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过 4 boolean[][] rowUsed = new boolean[9][10]; 5 boolean[][] colUsed = new boolean[9][10]; 6 boolean[][][] boxUsed = new boolean[3][3][10]; 7 // 初始化 8 for (int row = 0; row < board.length; row++) { 9 for (int col = 0; col < board[0].length; col++) { 10 int num = board[row][col] - '0'; 11 if (1 <= num && num <= 9) { 12 rowUsed[row][num] = true; 13 colUsed[col][num] = true; 14 boxUsed[row / 3][col / 3][num] = true; 15 } 16 } 17 } 18 // 递归尝试填充数组 19 helper(board, rowUsed, colUsed, boxUsed, 0, 0); 20 } 21 22 private boolean helper(char[][] board, boolean[][] rowUsed, boolean[][] colUsed, boolean[][][] boxUsed, int row, 23 int col) { 24 // 边界校验, 如果已经填充完成, 返回true, 表示一切结束 25 if (col == board[0].length) { 26 col = 0; 27 row++; 28 if (row == board.length) { 29 return true; 30 } 31 } 32 // 是空则尝试填充, 否则跳过继续尝试填充下一个位置 33 if (board[row][col] == '.') { 34 // 尝试填充1~9 35 for (int num = 1; num <= 9; num++) { 36 boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || boxUsed[row / 3][col / 3][num]); 37 if (canUsed) { 38 rowUsed[row][num] = true; 39 colUsed[col][num] = true; 40 boxUsed[row / 3][col / 3][num] = true; 41 board[row][col] = (char) ('0' + num); 42 if (helper(board, rowUsed, colUsed, boxUsed, row, col + 1)) { 43 return true; 44 } 45 board[row][col] = '.'; 46 rowUsed[row][num] = false; 47 colUsed[col][num] = false; 48 boxUsed[row / 3][col / 3][num] = false; 49 } 50 } 51 } else { 52 return helper(board, rowUsed, colUsed, boxUsed, row, col + 1); 53 } 54 return false; 55 } 56 }