一 、运用 回溯法 解数独
- 回溯法算法思想:(参考 回溯法)
定义:
回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
1、回溯法适用:有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法。
2、有组织的穷举式搜索:回溯法的基本做法是搜索或者有的组织穷尽搜索。它能避免搜索所有的可能性。即避免不必要的搜索。这种方法适用于解一些组合数相当大的问题。
3、搜索解空间树:回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含(剪枝过程),则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
找到子数独法
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子数独行标
let boxCol = (parseInt(col/3)*3)+i%3;//子数独列标
算法
- 行循环,嵌套列循环
- 找到没有数字的数组
if (board[i][j] == '.') {}
- 开始尝试填写数字1-9,isValid 检验填充数字是否有重复。有重复就回溯重新开始
for(let num = 1; num<10; num++) {
//检验填充数字的正确性
if (isValid(i,j,num)) {
board[i][j] = String(num);
//递归
if (solve(board)) {
return true;
}
board[i][j] = '.';
}
}
let isValid = (row,col,num) => {
//定位到每个小格子的坐标
for (let i = 0; i < 9; i++) {
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子数独行标
let boxCol = (parseInt(col/3)*3)+i%3;//子数独列标
//console.log(boxRow + '_' + boxCol);
if (board[row][i] == num || board[i][col] == num || board[boxRow][boxCol] == num) {
return false;
}
}
return true;
}
完整代码 js
var sd = new solveSudoku([
["5", "3", ".", ".", "7", ".", ".", ".", "."],
["6", ".", ".", "1", "9", "5", ".", ".", "."],
[".", "9", "8", ".", ".", ".", ".", "6", "."],
["8", ".", ".", ".", "6", ".", ".", ".", "3"],
["4", ".", ".", "8", ".", "3", ".", ".", "1"],
["7", ".", ".", ".", "2", ".", ".", ".", "6"],
[".", "6", ".", ".", ".", ".", "2", "8", "."],
[".", ".", ".", "4", "1", "9", ".", ".", "5"],
[".", ".", ".", ".", "8", ".", ".", "7", "9"]
]);
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var solveSudoku = function (board) {
//检验填充数字的正确性 row 行 col列 num 填充数字
let isValid = (row,col,num) => {
//循环尝试填充数字
for (let i = 0; i < 9; i++) {
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子数独行标
let boxCol = (parseInt(col/3)*3)+i%3;//子数独列标
//console.log(boxRow + '_' + boxCol);
if (board[row][i] == num || board[i][col] == num || board[boxRow][boxCol] == num) {
return false;
}
}
return true;
}
//声明一个块级变量
let solve =() => {
//循环行
for (let i = 0; i < 9; i++) {
//循环列
for (let j = 0; j < 9; j++) {
//判断填充资格
if (board[i][j] == '.') {
//开始循环数字
for(let num = 1; num<10; num++) {
//检验填充数字的正确性
if (isValid(i,j,num)) {
board[i][j] = String(num);
//递归
if (solve(board)) {
return true;
}
board[i][j] = '.';
}
}
return false;
}
}
}
return true;
}
solve(board);
console.log(board);
return board;
};