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

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.


A sudoku puzzle...


...and its solution numbers marked in red.

Note:

    • The given board contain only digits 1-9and the character '.'.
    • You may assume that the given Sudoku puzzle will have a single unique solution.
    • The given board size is always 9x9.

这道求解数独的题是在之前那道 Valid Sudoku 的基础上的延伸,之前那道题让我们验证给定的数组是否为数独数组,这道让求解数独数组,跟此题类似的有 PermutationsCombinationsN-Queens 等等,其中尤其是跟 N-Queens 的解题思路及其相似,对于每个需要填数字的格子带入1到9,每代入一个数字都判定其是否合法,如果合法就继续下一次递归,结束时把数字设回 '.',判断新加入的数字是否合法时,只需要判定当前数字是否合法,不需要判定这个数组是否为数独数组,因为之前加进的数字都是合法的,这样可以使程序更加高效一些,整体思路是这样的,但是实现起来可以有不同的形式。一种实现形式是递归带上横纵坐标,由于是一行一行的填数字,且是从0行开始的,所以当i到达9的时候,说明所有的数字都成功的填入了,直接返回 ture。当j大于等于9时,当前行填完了,需要换到下一行继续填,则继续调用递归函数,横坐标带入 i+1。否则看若当前数字不为点,说明当前位置不需要填数字,则对右边的位置调用递归。若当前位置需要填数字,则应该尝试填入1到9内的所有数字,让c从1遍历到9,每当试着填入一个数字,都需要检验是否有冲突,使用另一个子函数 isValid 来检验是否合法,假如不合法,则跳过当前数字。若合法,则将当前位置赋值为这个数字,并对右边位置调用递归,若递归函数返回 true,则说明可以成功填充,直接返回 true。不行的话,需要重置状态,将当前位置恢复为点。若所有数字都尝试了,还是不行,则最终返回 false。检测当前数组是否合法的原理跟之前那道 Valid Sudoku 非常的相似,但更简单一些,因为这里只需要检测新加入的这个数字是否会跟其他位置引起冲突,分别检测新加入数字的行列和所在的小区间内是否有重复的数字即可,参见代码如下:

解法一:

class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
helper(board, , );
}
bool helper(vector<vector<char>>& board, int i, int j) {
if (i == ) return true;
if (j >= ) return helper(board, i + , );
if (board[i][j] != '.') return helper(board, i, j + );
for (char c = ''; c <= ''; ++c) {
if (!isValid(board, i , j, c)) continue;
board[i][j] = c;
if (helper(board, i, j + )) return true;
board[i][j] = '.';
}
return false;
}
bool isValid(vector<vector<char>>& board, int i, int j, char val) {
for (int x = ; x < ; ++x) {
if (board[x][j] == val) return false;
}
for (int y = ; y < ; ++y) {
if (board[i][y] == val) return false;
}
int row = i - i % , col = j - j % ;
for (int x = ; x < ; ++x) {
for (int y = ; y < ; ++y) {
if (board[x + row][y + col] == val) return false;
}
}
return true;
}
};

还有另一种递归的写法,这里就不带横纵坐标参数进去,由于递归需要有 boolean 型的返回值,所以不能使用原函数。因为没有横纵坐标,所以每次遍历都需要从开头0的位置开始,这样无形中就有了大量的重复检测,导致这种解法虽然写法简洁一些,但击败率是没有上面的解法高的。这里的检测数组冲突的子函数写法也比上面简洁不少,只用了一个 for 循环,用来同时检测行列和小区间是否有冲突,注意正确的坐标转换即可,参见代码如下:

解法二:

class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
helper(board);
}
bool helper(vector<vector<char>>& board) {
for (int i = ; i < ; ++i) {
for (int j = ; j < ; ++j) {
if (board[i][j] != '.') continue;
for (char c = ''; c <= ''; ++c) {
if (!isValid(board, i, j, c)) continue;
board[i][j] = c;
if (helper(board)) return true;
board[i][j] = '.';
}
return false;
}
}
return true;
}
bool isValid(vector<vector<char>>& board, int i, int j, char val) {
for (int k = ; k < ; ++k) {
if (board[k][j] != '.' && board[k][j] == val) return false;
if (board[i][k] != '.' && board[i][k] == val) return false;
int row = i / * + k / , col = j / * + k % ;
if (board[row][col] != '.' && board[row][col] == val) return false;
}
return true;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/37

类似题目:

Valid Sudoku

Unique Paths III

参考资料:

https://leetcode.com/problems/sudoku-solver/

https://leetcode.com/problems/sudoku-solver/discuss/15853/Simple-and-Clean-Solution-C%2B%2B

https://leetcode.com/problems/sudoku-solver/discuss/15752/Straight-Forward-Java-Solution-Using-Backtracking

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Sudoku Solver 求解数独的更多相关文章

  1. [LeetCode] 37. Sudoku Solver 求解数独

    Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy  ...

  2. [LeetCode] Sudoku Solver 解数独,递归,回溯

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

  3. LeetCode:Valid Sudoku,Sudoku Solver(数独游戏)

    Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku bo ...

  4. [leetcode]37. Sudoku Solver 解数独

    Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy  ...

  5. LeetCode OJ:Sudoku Solver(数独游戏)

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

  6. Leetcode: Sudoku Solver

    July 19, 2015 Problem statement: Write a program to solve a Sudoku puzzle by filling the empty cells ...

  7. 037 Sudoku Solver 解数独

    写一个程序通过填充空格来解决数独.空格用 '.' 表示. 详见:https://leetcode.com/problems/sudoku-solver/description/ class Solut ...

  8. LEETCODE —— Sudoku Solver

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

  9. [LeetCode] Sudoku Solver(迭代)

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

随机推荐

  1. heart

    好久没写博客了,不想废话,直接欣赏效果! 点击这里,查看完美效果! 附完整代码: <!doctype html> <html> <head> <meta ch ...

  2. JavaWeb——tomcat安装及目录介绍

    一.web web可以说,就是一套 请求->处理->响应 的流程.客户端使用浏览器(IE.FireFox等),通过网络(Network)连接到服务器上,使用HTTP协议发起请求(Reque ...

  3. xmpp

    xmpp学习 下载: Openfire 服务器:Openfire 4.0.2 客户端:Spark 2.7.7 安装 Openfire安装: 根据提示一直下一步,服务器域名设置为:localhost(p ...

  4. 安装XAMPP遇到的问题及解决方法

    1.XAMPP无法启动Apache Xampp的获得和安装都十分简单,你只要到以下网址: http://www.apachefriends.org/zh_cn/xampp.html 下载xampp即可 ...

  5. 遍历datatable的方法汇总

    遍历datatable的方法方法一: DataTable dt = dataSet.Tables[]; ; i < dt.Rows.Count ; i++) { string strName = ...

  6. 做linux运维工程师,必须要掌握以下几个工具

    linux系统如果是学习可以选用redhat或centos,特别是centos在企业中用得最多,当然还会有其它版本的,但学习者还是以这2个版本学习就行,因为这两个版本都是兄弟,没区别的,有空可以再研究 ...

  7. iOS之获取App的LaunchImage

    作者:里脊串 授权本站转载. 启动图(LaunchImage)的管理其实在iOS开始中算比较简单的了,尤其是Xcode引入了xcassets之后,完全是傻瓜式的操作.但是有的时候我们还是需要在Laun ...

  8. iOS比较常用的第三方及实例(不断更新中)

    把平时看到或项目用到的一些插件进行整理,文章后面分享一些不错的实例,若你有其它的插件欢迎分享,不断的进行更新: 一:第三方插件 1:基于响应式编程思想的oc 地址:https://github.com ...

  9. 了解npm的文件结构(npm-folders)和配置文件(npm-mrc)

    一.npm的文件结构 npm的安装: 本地安装 1. 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm ...

  10. 几款Git GUI客户端工具

    工欲善其事,必先利其器. 作为一名开发人员,你不可能不知道git,无论你是开发自己的开源项目还是和团队一起进行大规模产品的开发,git都已经是源代码管理工具的首选.当然,那些hardcore deve ...