算法-解数独

377 阅读3分钟

这是我参与11月更文挑战的第29天,活动详情查看:2021最后一次更文挑战

一、数独

就是一个9*9的宫格,数字1-9每行每列只能出现一次,把九宫格分成3*3的小方格,每个3*3的方格中也只能出现一次。我们可以通过填充空格的方式解开,还是一样的可以通过递归和回溯方法,只不过判断条件变成横竖的1-9和3个宫格中的1-9的数字只能出现一次。

题目:解数独

var solveSudoku = function(board) {
    for(let i = 0;i<9;i++) {
        for(let j = 0;j<9;j++) {
            if(board[i][j] !== '.') continue;
                //放一个数字试试
                for(let k = 1;k<=9;k++) {
                    if(isValid(board,i,j,k.toString())) {
                        //可以放
                        board[i][j] = k.toString();
                        if(solveSudoku(board)) return true;
                        //回溯
                        board[i][j] = '.';
                    }
                }
                return false;
        }
    }
    return true;
}
//验证数字能不能放
function isValid(board,row,col,k) {
    const x = Math.floor(row/3) * 3;
    const y = Math.floor(col/3) * 3;
    for(let i = 0;i<9;i++) {
        if(board[row][i] === k || board[i][col] === k) {
            return false;
        }
    }
    //小方块
    for(let i = 0;i<3;i++) {
        for(let j = 0;j<3;j++) {
            if(board[x+i][y+j] === k) {
                return false
            }
        }
    }
    return true;
}

思路:

  • 需要在一个空格中放一个类似棋子一样的试一下,不行就换一不,算法之间都是相互有关系的,比如DFS数独就类似DFS深度优先搜索有点相似,不是空格就是数字,是空格就是用小数点代替。
  • 然后随便用一个数字在空格中代替,再到横竖和当前在的小方格内有没有数字和他一样,因为只能出现一次,这个可以作为终止条件。
  • 遍历9行和9列这样就是一个9*9的小方格,board就是一个二维数组,先判断一个终止条件,如果是数字不是空格就直接终止执行下一个,如果是小数点是空格,就要放一个1-9之间的数字,判断是否可以放单独做校验传入行、列、尝试的数字
  • 校验是否能放:当前的行每个数字是否有这个数字,当前列是否有这个数字,还要3*3的小宫格内是否有这个数字,这个就要定义x代表行和y代表列来拿到位置,x是当前位置除以3再取整,最后判断这个小方格里是否有数字等于当前数字。
  • 如果这个数字能放就要做递归,如果不能放就做回溯。

数独这道题主要就是递归和回溯比较麻烦,在做难题的时候一定要想好条件,把所有终止条件列好,比如这题就是三个终止条件:1、每行不能有重复的数字;2、每列不能有重复的数字;3、单独的3*3的小方格内不能有重复的数字。,然后再做验证方面的功能,最后再递归回溯检查一下没问题就可以了。