Leecode 37 解数独

题目:

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

空白格用 ‘.’ 表示。
在这里插入图片描述
一个数独。
在这里插入图片描述
答案被标成红色。

Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sudoku-solver
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

  1. 采用回溯解决,注意剪掉不必要的分支,提高效率;从前往后再空格中填数字(满足要求的数字),如果顺利填完就算完成,填不下去了就回溯;

代码分析:

  1. 通过boolean数组记录每一行(rowRecord)、每一列(colRecord)、每个区域(regionRecord)的数字填写情况,如第二行第三列填写了一个9,则:rowRecord[2][9] = true来表明,第二行的数字9已经存在了,同样的更新列和区域的数字填写情况;这样可以达到O(1)的时间复杂度下判断某个位置是否能够填写某个数字;(其实这种空间换时间的做法极大的增加了代码的复杂度,不记录,直接按照行、列、区域不能重复来判断数字是否适合填在某个位置也是可以的,只不过时间复杂度是O(n));
  2. 遍历整个二维数组,将已经填好的数字的标志填到rowRecord、colRecord以及regionRecord中;
  3. 遍历这个二维数组,如果是数字,则是已经填好的数字,不用管,直接下一个,如果是’.’,则需要填数字,遍历1-9,能符合要求,就填写该数字,然后继续下一个空格的填写,如果最终填完返回true则程序结束,如果到某个点所有数字都不符合要求,则回溯;

代码实现:

class Solution {
    public void solveSudoku(char[][] board) {
        if(board == null || board.length < 1) return;
        /**
        * colRecord : 记录0-8列中,每个数字是否已经填过了;
        * rowRecord : 同colRecord,不过记录的是行;
        * regionRecord : 同colRecord,记录的是区域中,数字的填写情况;
        */
        boolean[][] colRecord = new boolean[9][];
        boolean[][] rowRecord = new boolean[9][];
        boolean[][] regionRecord = new boolean[9][];
        for(int i = 0 ; i < 9;++i){
            colRecord[i] = new boolean[9];
            rowRecord[i] = new boolean[9];
            regionRecord[i] = new boolean[9];
        }
        //将已经事先填好的数字进行标记;
        initInvalidRecord(board,colRecord,rowRecord,regionRecord);
        //回溯解决问题
        solve(board,0,0,colRecord,rowRecord,regionRecord);
    }
    private void initInvalidRecord(char[][] board,boolean[][] colRecord,boolean[][] rowRecord,boolean[][] regionRecord){
        for(int i = 0 ;i < board.length;++i){
            for(int j = 0; j < board[0].length;++j){
                if(board[i][j] != '.'){
                    int number = board[i][j] - '1';
                    colRecord[j][number] = true;
                    rowRecord[i][number] = true;
                    regionRecord[i / 3 * 3 + j / 3][number] = true;
                }
            }
        }
    }
    public boolean solve(char[][] board,int row,int col,boolean[][] colRecord,boolean[][] rowRecord,boolean[][] regionRecord){
        if(row >= board.length || col >= board[0].length){ //成功填写所有数字
            return true;
        }
        if(board[row][col] == '.'){ //需要填写数字
            for(char c = '1'; c - '1' < 9; ++c){
                if(isValid(c,row,col,colRecord,rowRecord,regionRecord)){
                    board[row][col] = c;
                    setInvalid(board,row,col,colRecord,rowRecord,regionRecord);
                    ++col;
                    //下面的三目运算符实际上就是看列是否溢出,如溢出,则col=0,row = row+1;
                    int rowTemp = col >= board[0].length ? row+1 : row;
                    int colTemp = col >= board[0].length? 0: col;
                    if(solve(board,rowTemp ,colTemp,colRecord,rowRecord,regionRecord)){
                        return true;
                    } else { //问题没解决,需要回溯,还原状态;
                        --col;
                        setValid(board,row,col,colRecord,rowRecord,regionRecord);
                        board[row][col] = '.';
                    }
                }
            }
            return false;
        }else{//已预先填好数字,填写下一个
            ++col;
            //下面的三目运算符实际上就是看列是否溢出,如溢出,则col=0,row = row+1;
            if(solve(board,col >= board[0].length ? row+1 : row,col >= board[0].length? 0: col,colRecord,rowRecord,regionRecord)){
                return true;
            } else {
                return false;
            }
        }
    }
     public void setValid(char[][] board,int row,int col,boolean[][] colRecord,boolean[][] rowRecord,boolean[][] regionRecord){
         int number = board[row][col] - '1';
         colRecord[col][number] = false;
         rowRecord[row][number] = false;
         regionRecord[(row / 3) * 3 + col / 3][number] = false;
     }
    public void setInvalid(char[][] board,int row,int col,boolean[][] colRecord,boolean[][] rowRecord,boolean[][] regionRecord){
         int number = board[row][col] - '1';
         colRecord[col][number] = true;
         rowRecord[row][number] = true;
         regionRecord[(row / 3) * 3 + col / 3][number] = true;
     }
     public boolean isValid(char c,int row,int col,boolean[][] colRecord,boolean[][] rowRecord,boolean[][] regionRecord){
         int number = c - '1';
         if (colRecord[col][number] || rowRecord[row][number] || regionRecord[(row / 3) * 3 + col / 3][number]) {
             return false;
         } else {
             return true;
         }
     }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值