解数独(leetcode37)
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
解析:
可以考虑使用行优先的顺序依次枚举每一个空白格中填的数字,通过递归+回溯枚举所有可能的填法。
当递归到最后一个空白格后,还没有冲突,说明我们找到了答案;而如果当前空白格不能填下任何一个数字,就进行回溯。
由于每个数字在同一行,同一列,同一个九宫格只能出现一次,我们可以使用 line[ i ], column[ j ] , block[x][y]分别表示第i行,
第j列,和第(x,y)个九宫格中填下数字的情况。
方法一:
递归+回溯
我们用数组记录每个数字是否出现。
因为我们填写的数字范围是【1,9】,而数组的下标从0开始,
因此在存储时,我们使用一个长度为9的布尔类型的数组。如果数字 i+1 出现过,则令 第 i 个元素的值为 true 。
例如,line[2][3] = true,表示数字4在第2行已经出现过。则遍历第2行空白格时,不能再填4.
首先,遍历数独数组,标记空白格位置和已出现数字所在的行,列,九宫格信息。
然后开始递归枚举,判断位置为i和j位置的单元格,能否填入1-9,如果可以,继续递归判断下个空白格位置。否则,回溯。
public class Leetcode37 { private boolean[][] line = new boolean[9][9]; private boolean[][] column = new boolean[9][9]; private boolean[][][] block = new boolean[3][3][9]; private boolean valid = false; private List<int[]> spaces = new ArrayList<int[]>(); public static void main(String[] args) { // TODO Auto-generated method stub char[][] board = new char[9][9]; board[0]=new char[]{'5','3','.','.','7','.','.','.','.'}; board[1]=new char[]{'6','.','.','1','9','5','.','.','.'}; board[2]=new char[]{'.','9','8','.','.','.','.','6','.'}; board[3]=new char[]{'8','.','.','.','6','.','.','.','3'}; board[4]=new char[]{'4','.','.','8','.','3','.','.','1'}; board[5]=new char[]{'7','.','.','.','2','.','.','.','6'}; board[6]=new char[]{'.','6','.','.','.','.','2','8','.'}; board[7]=new char[]{'.','.','.','4','1','9','.','.','5'}; board[8]=new char[]{'.','.','.','.','8','.','.','7','9'}; Leetcode37 leet = new Leetcode37(); leet.solveSudoku(board); for(int i=0;i<9;i++){ for(int j=0;j<9;j++){ System.out.print(board[i][j]+" "); } System.out.println(); } } 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 { // 当数字i+1出现过时,令第i个元素的值为true,所以,这里表示第digit位置的值为true int digit = board[i][j] - '0' - 1; // 表示digit+1在第i行出现过,并且在第j列出现过,并且在位置为i/3,j/3的九宫格出现过 line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; } } } dfs(board, 0); } //递归+回溯 public void dfs(char[][] board, int pos) { if (pos == spaces.size()) {// 如果位置等于空白格的大小,则valid为true valid = true; return; } int[] space = spaces.get(pos); int i = space[0], j = space[1]; //遍历0-8的位置,实际是为了判断1-9这几个数字在对应位置是否已经出现过 for(int digit=0;digit<9&&!valid;++digit){ //在第i行,第j列,第i/3,j/3个九宫格中,digit都还没出现 if(!line[i][digit]&&!column[j][digit]&&!block[i/3][j/3][digit]){ line[i][digit]=column[j][digit]=block[i/3][j/3][digit]=true; board[i][j] = (char)(digit+'0'+1); dfs(board,pos+1); line[i][digit]=column[j][digit]=block[i/3][j/3][digit]=false; } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2020-04-07 MSSQL数据批量插入优化详细