题目:Write a program to solve a Sudoku puzzle by filling the empty cells.

  Empty cells are indicated by the character '.'.

  You may assume that there will be only one unique solution.

下面是一个数独的题目:

其解:

数独不是很了解,没做过。不过知道规则。就是在这个9x9的格纸中间添1到9的数字。使每一行不能重复,每一列也不能重复,然后上面那个粗线框起来的3x3的格纸中的数字也不能重复。

不知道这样的游戏有啥意义。。。

Anyway,这个和那个什么皇后的题很类似,一般用回溯。不过递归显得比较清晰。

添格子么。。。那不是一个一个添。顺序呢?我肯定是从左到右从上到下这么添。那代码我也这样写。对于每个格子,假设前面的所有格子已经添好了,并且构成了一个合理的棋盘。对当前的格子,如果没有填充,在查看该格子所在的行,列还有所在的3x3子格子后,我尝试每个剩余的可用数字,对每个数字,填充当前格子,然后问题就递归地变成了下面一个格子的填充问题。

如下图所示,我们要填充第三个格子。

我们首先查看Cell(0,2)所在的列2,标记出现的数字,也就是8;然后再查看其所在的行0,标记出现的数字5,3和7,最后查看它所在的3x3的格子,有5,3,6,9,和8。这样,3,5,6,7,8,9都被标记了,剩下的就是0,2,4三种可能。

我们不妨选一种,比如4,然后继续递归Cell(0,3)。如果这种选择不合理,在最后没有生成合理的结果,那在递归返回到Cell(0,2)的时候,我们在选择下一个可能的值就是了,例如2.但是这里有个要注意的是,如果当前所有的可能的值尝试都失败,一定要重新恢复当前Cell的值。再返回false。代码如下:

 /**
* 该函数假设从board[0][0]到
* board[row][col]之前的所有
* 格子都已经添满并且构成一个合理的board
* @param board 棋盘
* @param row 当前需要填充的cell的row
* @param col 当前需要填充的cell的col
* @return
*/
private static boolean solve(char[][]board, int row, int col){
int nextCol = (col + 1) % SIZE; //下一个需要填充的格子的列号
int nextRow = col == SIZE-1 ? row + 1 : row; //下一个需要填充的格子的行号
boolean[] set = new boolean[SIZE]; //记录当前格子可用的数字
if(board[row][col] == '.') {
scanColRowGrid(board, row, col, set);
for(int i = 0; i < SIZE; i++){
if(!set[i]){
board[row][col] = (char)('1' + i);
if(nextRow == SIZE) return true;
if(solve(board, nextRow, nextCol)) return true;
//else try next available number in this cell...
}
}
board[row][col] = '.'; //一定要恢复这个值
return false;
}else {
if(nextRow == SIZE) return true;
return solve(board, nextRow, nextCol);
}
}

其中的scanColRowGrid就是决定当前格可添的数字。

 /**
* 决定board[row][col]可填写的数字
* @param board
* @param row
* @param col
* @param set 当函数返回时,set[i]为false表明数字i+1可以填写到棋盘中。
* @return
*/
private static boolean[] scanColRowGrid(char[][] board, int row, int col, boolean[] set){
for(int i = 0; i < SIZE; i++){
if(board[row][i] >= '1' && board[row][i] <= '9') {
set[board[row][i] - '1'] = true;
}
}
for(int i = 0; i < SIZE; i++){
if(board[i][col] >= '1' && board[i][col] <= '9') {
set[board[i][col] - '1'] = true;
}
}
int grid = getGrid(row, col);
int st_row = 3 * (grid / 3);
int st_col = 3 * (grid % 3);
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
char c = board[st_row + i][st_col + j];
if(c >= '1' && c <= '9') {
set[c - '1'] = true;
}
}
}
return set;
} /**
* 通过行号和列号查询该格子所在的3x3格
* @param row
* @param col
* @return 0~8的数字,代表从左到右从上到下的3x3格标号
*/
private static int getGrid(int row, int col){
return 3 * (row / 3) + col / 3;
}

注意我们对3x3格的标号方式,是从左到右从上到下,标号为0~8,方便我们转换。

这道题虽然不难,但是比较经典,值得总结。

LeetCode 笔记系列十 Suduko的更多相关文章

  1. LeetCode 笔记系列 18 Maximal Rectangle [学以致用]

    题目: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones ...

  2. LeetCode 笔记系列16.3 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]

    题目:Given a string S and a string T, find the minimum window in S which will contain all the characte ...

  3. Python基础笔记系列十四:python无缝调用c程序

    本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! python语言可以对c程序代码进行调用,以弥补python语言低性能的缺 ...

  4. Python基础笔记系列十二:requests模块的简单应用

    本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! httpbin httpbin这个网站能测试 HTTP 请求和响应的各种信 ...

  5. Python基础笔记系列十:模块

    本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! 模块 #1.类比于java中的jar包,模块能让你能够有逻辑地组织你的Py ...

  6. LeetCode 笔记系列13 Jump Game II [去掉不必要的计算]

    题目: Given an array of non-negative integers, you are initially positioned at the first index of the ...

  7. LeetCode 笔记系列六 Reverse Nodes in k-Group [学习如何逆转一个单链表]

    题目:Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. ...

  8. LeetCode 笔记系列16.2 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]

    题目:Given a string S and a string T, find the minimum window in S which will contain all the characte ...

  9. LeetCode 笔记系列16.1 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]

    题目: Given a string S and a string T, find the minimum window in S which will contain all the charact ...

随机推荐

  1. JavaScript之Web通讯

    web通信,一个特别大的topic,涉及面也是很广的.因最近学习了 javascript 中一些 web 通信知识,在这里总结下.文中应该会有理解错误或者表述不清晰的地方,还望斧正! 一.前言 1. ...

  2. Python目录常用操作

    os.path.basename(path) #取文件名 os.path.getsize(path) #取文件大小 os.path.exists(path) #文件是否存在 os.path.dirna ...

  3. 0x00 译文:Windows桌面应用入门选择

    当你想要创建一个新的桌面应用的时候,第一个你需要做的决定是使用Win32 和COM 还是使用.NET两个选项. C++ 和 Win32 使你“离奖牌更近”,并使你可以获得最佳的应用性能..NET 使你 ...

  4. android.view.animation(2) - 插值器Interpolator

    public interface Interpolator implements TimeInterpolator android.view.animation.Interpolator Known ...

  5. MySQL中的Multi-Range Read优化

    MySQL 5.6开始支持Multi-Range Read(MRR)优化.目的是味儿减少磁盘的随机访问,并且将随机访问转化为较为顺序的数据访问,这对IO-bound类型的SQL查询语句可带来性能极大的 ...

  6. UIApplication深入学习

    多时候,我们不需要关心这个类,我们很少继承这个类,偶尔会调用这个类的api来实现一些功能,但是不可否认,这个类是iOS编程中很重要的一个概念.UIApplication的核心作用是提供了iOS程序运行 ...

  7. pycharm编写spark程序,导入pyspark包

    一种方法: File --> Default Setting --> 选中Project Interpreter中的一个python版本-->点击右边锯齿形图标(设置)-->选 ...

  8. headfirst设计模式swift版01

    headfirst设计模式这本书真好,准备用一个月学完.书里讲得很清楚了. 设计原则: 1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起. 2.针对接口编程,而不是针 ...

  9. 转:Linux下随机10字符病毒的清除

    病毒表现:网络流量暴满,疯狂地向香港的一个IP发数据,同时在top里面表现为随机的10位字母的进程,看/proc里面的信息,则为ls,cd之类常见的命令,CPU利用率也在top之首.杀死该进程后,会再 ...

  10. jQuery 中 attr() 和 prop() 方法的区别<转>

    前几天,有人给 Multiple Select 插件 提了问题: setSelects doesn't work in Firefox when using jquery 1.9.0 一直都在用 jQ ...