leetcode题解-37. Sudoku Solver

题目:Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character ‘.’.
You may assume that there will be only one unique solution.

好几天没刷题了,主要是因为最近在忙着看深度学习方面的论文和实现,所以耽搁了下来==今天赶紧把HashTable系列的最后一道题目–Sudoku Solver给做了。

解决本题的方法就是回溯法或者递归法。接下来我们看一下。思路一就是对没有数字的地方进行填充,至于填充哪个数字我们使用一个函数IsValid来判断其是否满足数独的要求。这种方法的思想就是回溯法。每当填充一个数字就继续判断下一个,直到成功。或者出现失败,则回溯到上一个点,把其填充的数字变成’.’,并尝试其他数字。甚至以智慧推到原始状态==代码如下所示:

    public void solveSudoku0(char[][] board) {
        if(board == null || board.length == 0)
            return;
        solve(board);
    }

    private boolean solve(char[][] board){
        //遍历整个数独的所有字符
        for(int i=0; i<board.length; i++){
            for(int j=0; j<board.length; j++){
                //若该点为空,则进行填充
                if(board[i][j] == '.'){
                    for(char c='1'; c<='9'; c++){
                        //选择要填充的数字
                        if(isValid(board, i, j, c)){
                            board[i][j] = c;
                            //填充完毕之后继续调用该函数填充下一个点
                            if(solve(board))
                                return true;
                            else
                                //如果solve(board)返回false,则说明前面的数字填充有误,将其还原。并判断下一个数字
                                board[i][j] = '.';
                        }
                    }
                    //如果1-9都无法满足则说明之前的数字填错了,回溯到原始状态
                    return false;
                }
            }
        }
        //直到所有的店=点都被填充完毕,返回true
        return true;
    }

    private boolean isValid(char[][] board, int row, int col, char c){
        for(int i = 0; i < 9; i++) {
            if(board[i][col] != '.' && board[i][col] == c) return false; //check row
            if(board[row][i] != '.' && board[row][i] == c) return false; //check column
            if(board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] != '.' &&
                    board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; //check 3*3 block
        }
        return true;
    }

上面的这种回退方法会重复的判断很多信息,导致执行效率比较低,只击败了30%的选手。接下来我们介绍另外一种方法,其可以击败95%的用户。其主要思路是使用3个二维数组来保存面板的行,列,九宫格信息,这样就省去了循环调用isValid函数进行判断的过程,大大的提高了函数执行的效率。代码入下:

     int[][] map1;  //map1, map2, map3 represents the row, coloum, grid check of suduku.
     int[][] map2;       //e.g. map1[2][3] means the number '4' has been existed in row 3.
     int[][] map3;
     char[][] board;
     public void solveSudoku(char[][] board) {
         this.board = board;
         map1 = new int[9][9];
         map2 = new int[9][9];
         map3 = new int[9][9];
         // initialization with the original board.
         for(int i = 0; i<9; i++){
             for(int j = 0; j<9; j++){
                 if(board[i][j]!='.'){
                     int num = board[i][j]-'0'-1;
                     map1[i][num] = 1;
                     map2[j][num] = 1;
                     map3[(i/3)*3+j/3][num] = 1;
                     }
               }
          }
          solve(0);
    }

    private boolean solve(int count){
        if(count>=81 ){ // if the pointer exceeds the end of the board,there is a solution.
            return true;
         }
         for(int i = count; i<81; i++){  // the loop starts from the current call.
             int ii = i/9;     // transfer the 1 dimensional position to 2 dim position.
             int jj = i%9;
             if(board[ii][jj]!='.') continue;
             else{
                 for(int k =0; k<9; k++){
                 // if there is a conflict, we choose the next number from 1 to 9.
                 if(map1[ii][k]==1||map2[jj][k]==1||map3[(ii/3)*3+jj/3][k]==1) continue;
                 else{
                       board[ii][jj] = (char)(k+49);
                       map1[ii][k] = 1;
                       map2[jj][k] = 1;
                       map3[3*(ii/3)+jj/3][k] = 1;
                       if(solve(ii*9+jj+1)==true) return true;
                       // If there is not a solution found in the next recursion call, 
                       // then we recover, the current board and restriction arrays.
                       map1[ii][k] = 0;
                       map2[jj][k] = 0;
                       map3[3*(ii/3)+jj/3][k] = 0;
                       board[ii][jj] = '.';
                  }
             }
       // If there is no solution found from 1 to 9, then we go back to the last recursion call.
             return false;
       }
    }
    // This is trivial just to be correspond with the return type.
    return true;
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值