乘风破浪:LeetCode真题_037_Sudoku Solver
乘风破浪:LeetCode真题_037_Sudoku Solver
一、前言
这次我们对于上次的模型做一个扩展并求解。
二、Sudoku Solver
2.1 问题




2.2 分析与解决
这道题让我们按照规则,填写数独表上的内容,并且已知假设答案是唯一的。这里我们直到一个3*3的方格内的数字不能重复,因此须要填写完成,就需要所有的数字,因此我们可以尝试使用图遍历中的深度优先和广度优先遍历来不断地试探,直到得到最后的结果。同样的递归也能达成上面的要求。
class Solution {
int[][] hCounts;
int[][] vCounts;
int[][][] sqCounts;
public void solveSudoku(char[][] board) {
hCounts = new int[9][9];
vCounts = new int[9][9];
sqCounts = new int[3][3][9];
for (int row=0;row<9;row++) {
for (int col=0;col<9;col++)
if (board[row][col] != '.')
set(board, row, col, board[row][col]);
}
solve(board, 0, 0);
}
private boolean solve(char[][] board, int row, int col) {
if (row == board.length)
return true;
if (col == board[0].length)
return solve(board, row+1, 0);
if (board[row][col] != '.')
return solve(board, row, col+1);
for (int i=1;i<10;i++) {
char n = (char)('0' + i);
if (canAdd(row, col, n)) {
set(board, row, col, n);
if (solve(board, row, col+1))
return true;
unset(board, row, col, n);
}
}
return false;
}
private boolean canAdd(int row, int col, char c) {
int n = c-'0'-1;
return hCounts[row][n] == 0 && vCounts[col][n] == 0 && sqCounts[row/3][col/3][n] == 0;
}
private void set(char[][] board, int row, int col, char c) {
board[row][col] = c;
int n = c-'0'-1;
hCounts[row][n]++;
vCounts[col][n]++;
sqCounts[row/3][col/3][n]++;
}
private void unset(char[][] board, int row, int col, char c) {
board[row][col] = '.';
int n = c-'0'-1;
hCounts[row][n]--;
vCounts[col][n]--;
sqCounts[row/3][col/3][n]--;
}
}
这道题的算法可以说是非常经典的,进行了一些抽象,首先是初始化,通过三个数组来检验能不能添加元素进去。方法也很简单,如果存在过某个数值,就加一,然后再添加的时候需要判断一下是不是能够加入进去。
private boolean canAdd(int row, int col, char c) {
int n = c-'0'-1;
return hCounts[row][n] == 0 && vCounts[col][n] == 0 && sqCounts[row/3][col/3][n] == 0;
}
private void set(char[][] board, int row, int col, char c) {
board[row][col] = c;
int n = c-'0'-1;
hCounts[row][n]++;
vCounts[col][n]++;
sqCounts[row/3][col/3][n]++;
}
之后我们从最开始的[0,0]按行遍历,通过递归算法,如果能将字符加入进去就加入,继续调用,不能的话就撤回,然后继续遍历,先对每一行的每一列的元素进行遍历,当完成之后遍历下一行,直至结束。
private boolean solve(char[][] board, int row, int col) {
if (row == board.length) //已经遍历到表外了,结束,成功。
return true;
if (col == board[0].length) //开始下一行
return solve(board, row+1, 0);
if (board[row][col] != '.') //不为.则继续下一列。
return solve(board, row, col+1);
for (int i=1;i<10;i++) {
char n = (char)('0' + i);
if (canAdd(row, col, n)) {
set(board, row, col, n);
if (solve(board, row, col+1))
return true;
unset(board, row, col, n);//不成功,回退
}
}
return false; //最后都没成功,返回false
}
三、总结
涉及到图的问题,让我们想到了八皇后问题,同样的联想到这个题的解法。
乘风破浪:LeetCode真题_037_Sudoku Solver的更多相关文章
- 乘风破浪:LeetCode真题_041_First Missing Positive
乘风破浪:LeetCode真题_041_First Missing Positive 一.前言 这次的题目之所以说是难,其实还是在于对于某些空间和时间的限制. 二.First Missing Posi ...
- 乘风破浪:LeetCode真题_040_Combination Sum II
乘风破浪:LeetCode真题_040_Combination Sum II 一.前言 这次和上次的区别是元素不能重复使用了,这也简单,每一次去掉使用过的元素即可. 二.Combination Sum ...
- 乘风破浪:LeetCode真题_039_Combination Sum
乘风破浪:LeetCode真题_039_Combination Sum 一.前言 这一道题又是集合上面的问题,可以重复使用数字,来求得几个数之和等于目标. 二.Combination Sum ...
- 乘风破浪:LeetCode真题_038_Count and Say
乘风破浪:LeetCode真题_038_Count and Say 一.前言 这一道题目,很类似于小学的问题,但是如果硬是要将输入和结果产生数值上的联系就会产生混乱了,因此我们要打破思维定势. ...
- 乘风破浪:LeetCode真题_036_Valid Sudoku
乘风破浪:LeetCode真题_036_Valid Sudoku 一.前言 有的时候对于一些基础知识的掌握,对我们是至关重要的,比如ASCII重要字符的表示,比如一些基本类型的长度. 二.Valid ...
- 乘风破浪:LeetCode真题_035_Search Insert Position
乘风破浪:LeetCode真题_035_Search Insert Position 一.前言 这次的问题比较简单,也没有限制时间复杂度,但是要注意一些细节上的问题. 二.Search Insert ...
- 乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array
乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array 一.前言 这次我们还是要改造二分搜索,但是想法却 ...
- 乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array
乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array 一.前言 将传统的问题进行一些稍微的变形,这个时候我们可能无所适从了,因此还是实践出真知, ...
- 乘风破浪:LeetCode真题_032_Longest Valid Parentheses
乘风破浪:LeetCode真题_032_Longest Valid Parentheses 一.前言 这也是非常有意思的一个题目,我们之前已经遇到过两个这种括号的题目了,基本上都要用到堆栈来解决,这次 ...
随机推荐
- 我搞zabbix的那两天(1)
摘要:在生产环境上对服务器进行网络参数(比如CPU.内存等)的监控是很必要的,比如当服务器网络参数如内存不够用.磁盘空间快要占满时及时通知运维人员进行处理,保证服务器系统的安全.而zabbix就是这么 ...
- .18-浅析webpack源码之compile流程-rules参数处理(1)
Tips:写到这里,需要对当初的规则进行修改.在必要的地方,会在webpack.config.js中设置特殊的参数来跑源码,例如本例会使用module:{rules:[...]}来测试,基本上测试参数 ...
- .5-浅析express源码之Router模块(1)-默认中间件
模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...
- Docker基础-Docker数据管理
1.数据卷 数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount操作. 数据卷可以提供很多有用的特性: 1.数据卷可以在容器之间共享和重用,容器间传递 ...
- Repeater控件添加onmouseover和onmouseout事件
网友有问题,在Repeater控件中,需要添加onmouseover和onmouseout事件功能.Insus.NET有叫他参考<onmouseover和onmouseout在Repeater控 ...
- Spring Security认证配置(三)
学习本章之前,可以先了解下上篇Spring Security认证配置(二) 本篇想要达到这样几个目的: 1.登录成功处理 2.登录失败处理 3.调用方自定义登录后处理类型 具体配置代码如下: spri ...
- git 使用 VisualStudio 比较分支更改
有时候需要比较两个分支的不同,这时如果提交到 github ,那么默认就可以看到.但是这时因为没有ide的高亮或者其他的功能,看起来觉得不好 默认的 VisualStudio 比较文件比 github ...
- redis缓存工具类,提供序列化接口
1.序列化工具类 package com.qicheshetuan.backend.util; import java.io.ByteArrayInputStream; import java.io. ...
- stylus常用写法
带参数 border-radius(val) -webkit-border-radius: val -moz-border-radius: val border-radius: val button ...
- PHP 基础总结
PHP(Hypertext Preprocessor)是一种被广泛应用的开源通用脚本语言,尤其适用于Web开发.可用于服务端脚本.命令行脚本.桌面应用程序三大领域. PHP 的 SAPI(服务器应用程 ...