【算法30天:Day30】第七章回溯算法 LeetCode 解数独(37)

79 阅读2分钟

题目三:

image.png

完整代码:

本题中棋盘的每一个位置都要放一个数字,并检查数字是否合法,解数独的树形结构要比N皇后更宽更深

一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!

var solveSudoku = function (board) {
  function backtracking() {
    //「一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,
    // 一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!」
    for (let i = 0; i < board.length; i++) {
      // 遍历行
      for (let j = 0; j < board[0].length; j++) {
        // 遍历列
        if (board[i][j] !== ".") continue // 跳过原始数字
        for (let val = 1; val <= 9; val++) {
          if (isValid(i, j, `${val}`, board)) {
            board[i][j] = `${val}` // (i, j) 这个位置放val是否合适
            if (backtracking(board)) {
              return true // 如果找到合适一组立刻返回
            }
            board[i][j] = "." // 回溯
          }
        }
        // 9个数都试完了,都不行,那么就返回false
        return false
        // 因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!
        // 那么会直接返回, 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!」
      }
    }
    // 遍历完没有返回false,说明找到了合适棋盘位置了
    return true
  }
  /**
   * 判断棋盘是否合法有如下三个维度:
   *     同行是否重复
   *     同列是否重复
   *     9宫格里是否重复
   */
  function isValid(row, col, val, board) {
    let len = board.length
    // 行不能重复
    for (let i = 0; i < len; i++) {
      if (board[row][i] === val) {
        return false
      }
    }
    // 列不能重复
    for (let i = 0; i < len; i++) {
      if (board[i][col] === val) {
        return false
      }
    }
    // 9宫格不能重复 将坐标初始为每个小方格的左上角 
    let startRow = Math.floor(row / 3) * 3
    let startCol = Math.floor(col / 3) * 3

    for (let i = startRow; i < startRow + 3; i++) {
      for (let j = startCol; j < startCol + 3; j++) {
        if (board[i][j] === val) {
          return false
        }
      }
    }
    return true
  }
  backtracking(board)
  return board
}