【leetcode】 37. 解数独

一 、运用 回溯法 解数独

  • 回溯法算法思想:(参考 回溯法

定义:

回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

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;
};

猜你喜欢

转载自blog.csdn.net/weixin_36851500/article/details/103978213