zoukankan      html  css  js  c++  java
  • [LeetCode] 37. Sudoku Solver

    解数独。需要先做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 }

    LeetCode 题目总结

  • 相关阅读:
    家谱树 x
    codevs 1231 最优布线问题 x(find函数要从娃娃抓起系列)
    洛谷 P1546 最短网络 Agri-Net x
    codevs 5969 [AK]刻录光盘x
    家谱(gen)x
    [POJ2594]Treasure Exploration(最小路径覆盖变种,floyd算法,匈牙利算法)
    [HDOJ5855]Less Time, More profit(最大权闭合子图,二分,最大流)
    [HDOJ1054]Strategic Game(最小点覆盖,最大二分匹配,HK算法)
    [HDOJ3829]Cat VS Dog(最大独立集)
    [HDOJ3488]Tour(二分图最小匹配,KM算法)
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12735614.html
Copyright © 2011-2022 走看看