Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) 数独部分空格内已填入了数字,空白格用 '.' 表示。
示例 1:
输入:board = [["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"]]
输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
- board.length == 9
- board[i].length == 9
- board[i][j] 是一位数字或者 '.'
- 题目数据 保证 输入数独仅有一个解
题解
这种棋盘类的题,都是可以通过 回溯 的一个方式来解决。
这道题的难点,在于 return 的时机,需要想明白 何时进行 return,值 true 或是 false。
判断棋盘是否出现重复,则判断当前行,当前列,当前3*3 网格内是否存在这个值 即可。
回溯
const solveSudoku = (board) => {
const boardRowLength = board.length
const boardColumnLength = board[0].length
const isRepeat = (x, y, value) => {
// 判断当前行是否存在
if (board[x].indexOf(value) !== -1) return true
// 判断当前列是否存在
for (let i = 0; i < boardRowLength; i++) {
if (board[i][y] === value) {
return true
}
}
// 判断3*3网格是否存在
const startX = Math.floor(x / 3) * 3
const startY = Math.floor(y / 3) * 3
const endX = startX + 3
const endY = startY + 3
for (let i = startX; i < endX; i++) {
for (let j = startY; j < endY; j++) {
if (board[i][j] === value) {
return true
}
}
}
return false
}
const search = () => {
for (let i = 0; i < boardRowLength; i++) {
for (let j = 0; j < boardColumnLength; j++) {
// 先判断 是否为 .
if (board[i][j] !== '.') continue
// 如果为点 则进行遍历
for (let val = 1; val <= 9; val++) {
// 判断是否重复
if (!isRepeat(i, j, `${val}`)) {
// 不重复
board[i][j] = `${val}`
// 进行递归 操作,如果找到,则返回true,代表找到了
if (search()) {
return true
}
board[i][j] = '.'
}
}
// 如果 1~9 ,这几个数都不可以的话,就返回false
return false
}
}
// 如果遍历完后,没有发现false,那么就返回true,说明已经找到符合的棋盘
return true
}
search()
return board
}
总结
该题目 29 :回溯,可以很清楚的解决我们的棋盘类问题,只要不符合,我们就回退即可,直到找到我们要的结果。