携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
写在前面
剪枝,在算法搜索中其实非常常用,不管是之前的广度优先算法(BFS)还是深度优先算法(DFS)、抑或是其他搜索算法。
那为什么需要剪枝呢?
前两篇我们遍历二叉树的时候,不管用的是广度优先算法还是深度优先算法,都是逐一遍历树的每个节点,这对于数据量小的树来说,当然没有问题,但如果把数据量放大,再逐一遍历,再进行回溯,效率就会很慢。这个时候就需要我们先进行判断,不满足要求的分支直接剪掉,这就是剪枝。
有效数独
描述
如下图,是个数独格,里面填写了部分数字,但未必有效,对有效的评判标准有三个:
- 数字
1-9在每一行只能出现一次 - 数字
1-9在每一列只能出现一次 - 数字
1-9在每一个以粗实线分隔的3x3宫内只能出现一次
分析
判断有效数独,其实就是一种剪枝的行为,当我们在完成数独之前,第一步就是要判断是否是有效数独,且后面都会不断进行校验。
既然对有效数独的判断标准有三个,那我们逐个在判断即可。
- 先定义每组数据是否有效的方法,在执行过程中,任何一组不符合,即返回false,都符合则返回true
- 行判断最简单,分别校验每行是否有效
- 列判断需要用到二层循环来倒序组装成新的一组数来执行判断
- 块判断,总共有9块,成组放入对象中
代码
/**
* @param {character[][]} board
* @return {boolean}
*/
var isValidSudoku = function(board) {
let _block = {}
for (let i = 0; i < 9; i++) {
// 行校验
if(!_valid(board[i])) return false
let _column = []
let _blockRow = Math.floor(i/3)
for (let j = 0; j < 9; j++) {
_column.push(board[j][i])
let _blockColomn = Math.floor(j/3)
const _index = _blockRow*3+_blockColomn
if (!_block[_index]) {
_block[_index] = []
}
_block[_index].push(board[i][j])
}
// 列校验
if(!_valid(_column)) return false
}
// 块校验
for (let k = 0; k < 9; k++) {
if(!_valid(_block[k])) return false
}
function _valid (arr = []) {
const filter = arr.filter(val => val !== '.')
const set = new Set(filter)
return filter.length === set.size
}
return true
};