[LeetCode] Sudoku Solver 求解数独
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9must occur exactly once in each row. - Each of the digits
1-9must occur exactly once in each column. - Each of the the digits
1-9must occur exactly once in each of the 93x3sub-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 的基础上的延伸,之前那道题让我们验证给定的数组是否为数独数组,这道让求解数独数组,跟此题类似的有 Permutations,Combinations,N-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
类似题目:
Unique Paths III
参考资料:
https://leetcode.com/problems/sudoku-solver/
https://leetcode.com/problems/sudoku-solver/discuss/15853/Simple-and-Clean-Solution-C%2B%2B
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Sudoku Solver 求解数独的更多相关文章
- [LeetCode] 37. Sudoku Solver 求解数独
Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy ...
- [LeetCode] Sudoku Solver 解数独,递归,回溯
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- LeetCode:Valid Sudoku,Sudoku Solver(数独游戏)
Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku bo ...
- [leetcode]37. Sudoku Solver 解数独
Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy ...
- LeetCode OJ:Sudoku Solver(数独游戏)
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- Leetcode: Sudoku Solver
July 19, 2015 Problem statement: Write a program to solve a Sudoku puzzle by filling the empty cells ...
- 037 Sudoku Solver 解数独
写一个程序通过填充空格来解决数独.空格用 '.' 表示. 详见:https://leetcode.com/problems/sudoku-solver/description/ class Solut ...
- LEETCODE —— Sudoku Solver
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
- [LeetCode] Sudoku Solver(迭代)
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...
随机推荐
- 网站实现微信登录之回调函数中登录逻辑的处理--基于yii2开发的描述
上一篇文章网站实现微信登录之嵌入二维码中描述了如何在自己的登录页面内嵌入登录二维码,今天的这篇文章主要是描述下在扫码成功之后微信重定向回网站后登录逻辑的处理,其实也就是验证身份信息,授权用户登录的逻辑 ...
- 自己用js实现全屏滚动
参照fullPage.js的效果,用自己的想法实现的. 实现的效果:1.全屏滚动,滚动一下齿轮就会滚动全屏. 2.自适应缩放,无论怎么改变窗口的大小,都会保证用一个元素占满全屏. 下一步计划: 1.改 ...
- WebApi跨域问题
1.通过Nuget下载CORS安装包 2.在WebApiConfig.cs文件中注册CORS 3.在全局文件启用CORS支持 4.在控制器上添加头
- 代码的坏味道(11)——霰弹式修改(Shotgun Surgery)
坏味道--霰弹式修改(Shotgun Surgery) 霰弹式修改(Shotgun Surgery) 类似于 发散式变化(Divergent Change) ,但实际上完全不同.发散式变化(Diver ...
- 【那些年关于java多态应用】
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal { public abstract void Say();} 子类: public class ...
- 『.NET Core CLI工具文档』(二).NET Core 工具遥测(应用信息收集)
说明:本文是个人翻译文章,由于个人水平有限,有不对的地方请大家帮忙更正. 原文:.NET Core Tools Telemetry 翻译:.NET Core 工具遥测(应用信息收集) .NET Cor ...
- 关于Linux下转换oracle字符集
前阵子给以同事导oracle数据库,但是发现导入后数据都是乱码,下面是自己解决这个问题的一些小整理. 比如: #su oralce $export ORACLE_SID=orcl $export OR ...
- CSS3 @font-face的使用
首先我们一起来看看@font-face的语法规则: @font-face { font-family: <YourWebFontName>; src: <source> [&l ...
- react-echarts之折线图的显示
react中想要实现折线图和饼图的功能,需要引入react-echarts包,然后再实现折线图的功能.我这里引用的版本是:0.1.1.其他的写法参echarts官网即可.下面详细讲解的是我在react ...
- 长按TextField或TextView显示中文的粘贴复制
首先要确保手机当前系统为中文,只需要在 plist 文件中添加 Localized resources can be mixed = YES 就行了