乘风破浪: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 一.前言 这也是非常有意思的一个题目,我们之前已经遇到过两个这种括号的题目了,基本上都要用到堆栈来解决,这次 ...
随机推荐
- Jetty学习四:部署到Jetty
转自:http://www.tuicool.com/articles/NrENjq Web应用的框架 标准Jetty发布版本能部署标准servlet Spec Web应用和Jetty内部Context ...
- little eye 精简版
https://github.com/salomon1184/PerfMan/ 代码没整理,特乱 来源于一次聊天,一天半做完,考虑继续深做
- 数据存储之第三方FMDB
上周四.周五在忙公司的事情和炒股,没来得及更新博客,这周就补一下,学习总结下FMDB. FMDB是对sqlite的封装,特别是在多线程情况下,使用sqlite是非常麻烦,而使用FMDB相对简单,下面是 ...
- SpringBoot结合Swagger2自动生成api文档
首先在pom.xml中添加如下依赖,其它web,lombok等依赖自行添加 <dependency> <groupId>io.springfox</groupId> ...
- Mybatis的自动映射autoMappingBehavior与mapUnderscoreToCamelCase
autoMappingBehavior 在Mybatis的配置文件中添加settings属性的autoMappingBehavior <settings> <setting name ...
- Java - List总结
Java提高篇(三二)-----List总结 前面LZ已经充分介绍了有关于List接口的大部分知识,如ArrayList.LinkedList.Vector.Stack,通过这几个知识点可以对List ...
- 如何在SpringMVC中使用REST风格的url
如何在SpringMVC中使用REST风格的url 1.url写法: get:/restUrl/{id} post:/restUrl delete:/restUrl/{id} put:/restUrl ...
- numpy练习题
1. 导入numpy库并简写为 np import numpy as np 2. 打印numpy的版本和配置说明 print(np.__version__) print(np.show_config( ...
- JConsole连接远程linux服务器配置
1.在远程机的tomcat的catalina.sh中加入配置 (catalina.sh路径在tomcat/bin下面 如/usr/local/tomcat/bin) if [ "$1&quo ...
- Java 基础知识总结 3
13.java类集 类集实际上是一个动态的对象数组,与一般的对象数组不同,类集中的对象内容可以任意扩充. 类集的特征: 1)这种框架是高性能的 2)框架必须允许不同类型的类集以相同的方式和高度互操作方 ...