求解9*9数独

求解9*9数独


题目说明:
通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:

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

空白格用 ‘.’ 表示。

一个数独:

答案被标成红色:

提示:

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

问题分析:
可以考虑按照**“行优先”的顺序依次枚举每一个空白格中填的数字,通过递归 + 回溯**的方法枚举所有可能的填法。当递归到最后一个空白格后,如果仍然没有冲突,说明找到了答案;在递归的过程中,如果当前的空白格不能填下任何一个数字,进行回溯。
由于每个数字在同一行、同一列、同一个九宫格中只会出现一次,可以使用 row[i],col[j],blo[x][y]分别表示第 i 行,第 j 列,第 (x,y)个九宫格中填写数字的情况。
递归思路:
用一个数组记录每个数字是否出现,可以填写的数字范围为 [1,9],数组的下标从 000 开始,在存储时,使用一个长度为 999 的布尔类型的数组,其中 i 个元素的值为 True,当且仅当数字 i+1 出现过。
当遍历到第 i 行第 j 列的位置:
如果该位置是一个空白格,将其加入一个用来存储空白格位置的列表中,方便后续的递归操作;
如果该位置是一个数字 x,需要将 row[i][x−1],col[j][x−1], blo[⌊i/3⌋][⌊j/3⌋][x−1]置为 True。
算法求解部分如下:

class Solution {
    private boolean[][] row=new boolean[9][9];
    private boolean[][] col=new boolean[9][9];
    private boolean[][][] blo=new boolean[3][3][9];
    private boolean valid=false;
    private List<int[]> spaces=new ArrayList<>();
    public void solveSudoku(char[][] board) {
        //递归
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]=='.'){
                    //保存空位置
                    spaces.add(new int[]{i,j});
                }
                //在该位置数字三个区间标记
                else{
                    int dig=board[i][j]-'0'-1;
                    row[i][dig]=col[j][dig]=blo[i/3][j/3][dig]=true;
                }
            }
        }
        //第一个空位置开始值的填入
        dfs(board,0);
    }
    private void dfs(char[][] board,int pos){
        if(pos==spaces.size()){
            valid=true;
            return ;
        }
        int[] space=spaces.get(pos);
        int i=space[0],j=space[1];
        //遍历判断该值是符合
        for(int dig=0;dig<9 && !valid;dig++){
            if(!row[i][dig] && !col[j][dig] && !blo[i/3][j/3][dig]){
                row[i][dig]=col[j][dig]=blo[i/3][j/3][dig]=true;
                board[i][j]=(char)(dig+'0'+1);
                //下一个空值位置
                dfs(board,pos+1);
                //递归之后的值恢复
                row[i][dig]=col[j][dig]=blo[i/3][j/3][dig]=false;
            }
        }
    }
}
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数独问题是一种经典的求解问题,回溯法是其中一种常用的算法。下面是用Java实现数独问题的回溯法: ```java public class SudokuSolver { private int[][] board; private static final int EMPTY = 0; private static final int SIZE = 9; public SudokuSolver(int[][] board) { this.board = new int[SIZE][SIZE]; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { this.board[i][j] = board[i][j]; } } } public boolean solve() { int row = -1; int col = -1; boolean isEmpty = true; // 找到第一个空格 for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == EMPTY) { row = i; col = j; isEmpty = false; break; } } if (!isEmpty) { break; } } // 如果没有空格了,则数独已经解决 if (isEmpty) { return true; } // 尝试填充数字 for (int num = 1; num <= SIZE; num++) { if (isValid(row, col, num)) { board[row][col] = num; if (solve()) { return true; } board[row][col] = EMPTY; } } return false; } // 检查当前数字是否有效 private boolean isValid(int row, int col, int num) { for (int i = 0; i < SIZE; i++) { if (board[row][i] == num) { return false; } if (board[i][col] == num) { return false; } int rowOffset = 3 * (row / 3); int colOffset = 3 * (col / 3); if (board[rowOffset + (i / 3)][colOffset + (i % 3)] == num) { return false; } } return true; } public void print() { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { System.out.print(board[i][j] + " "); } System.out.println(); } } public static void main(String[] args) { int[][] board = new int[][] { {8, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 3, 6, 0, 0, 0, 0, 0}, {0, 7, 0, 0, 9, 0, 2, 0, 0}, {0, 5, 0, 0, 0, 7, 0, 0, 0}, {0, 0, 0, 0, 4, 5, 7, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 3, 0}, {0, 0, 1, 0, 0, 0, 0, 6, 8}, {0, 0, 8, 5, 0, 0, 0, 1, 0}, {0, 9, 0, 0, 0, 0, 4, 0, 0} }; SudokuSolver solver = new SudokuSolver(board); solver.solve(); solver.print(); } } ``` 在上面的代码中,我们定义了一个`SudokuSolver`类,其中包含了一个9x9的数独矩阵`board`。`solve()`方法通过回溯法来解决数独问题,`isValid()`方法用来检查当前数字是否有效,`print()`方法用来输出结果。 在`main()`方法中,我们定义了一个数独矩阵,并将其传递给`SudokuSolver`类来解决。最后输出结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值