初级搜索
优化方式:不重复(fibonacci)、剪枝(生成括号问题)
搜索方向:
- DFS:深度优先搜索
- BFS:广度优先搜索
双向搜索、启发式搜索(优先级搜索)
剪枝
状态树进行搜索的时候,如果发现这个分支已经处理过,我们可以把它暂存在缓存里面,整个分支就可以剪掉,不需要手动进行计算。
有些时候分支不够好,是比较差的分支或者次优的分支,我们也可以把它剪掉。
回溯法
回溯法采用试错的思想,尝试分布的去解决一个问题。在分布解决问题的过程中,当它通过尝试发现现有的分布答案不能得到有效的正确的解答的时候,它讲取消上一步甚至是上几步的计算,再通过其它的可能的分布解答再次尝试寻找问题的答案。
回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
- 找到一个可能存在的正确的答案
- 在尝试了所有可能的分布方法后宣告该问题没有答案
在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。
相关题目
爬楼梯(阿里巴巴、腾讯、字节跳动在半年内面试常考)
括号生成(亚马逊、Facebook、字节跳动在半年内面试中考过)
N 皇后(亚马逊、苹果、字节跳动在半年内面试中考过)
有效的数独(亚马逊、苹果、微软在半年内面试中考过)
解数独(亚马逊、华为、微软在半年内面试中考过)
// 有效的数独
/**
* @param {character[][]} board
* @return {boolean}
*/
var isValidSudoku = function(board) {
const rows = new Array(9).fill(0).map(() => new Array(9).fill(0));
const columns = new Array(9).fill(0).map(() => new Array(9).fill(0));
const subboxes = new Array(3).fill(0).map(() => new Array(3).fill(0).map(() => new Array(9).fill(0)));
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const c = board[i][j];
if (c !== '.') {
const index = c.charCodeAt() - '0'.charCodeAt() - 1;
rows[i][index]++;
columns[j][index]++;
subboxes[Math.floor(i / 3)][Math.floor(j / 3)][index]++;
if (
rows[i][index] > 1 ||
columns[j][index] > 1 ||
subboxes[Math.floor(i / 3)][Math.floor(j / 3)][index] > 1
) {
return false;
}
}
}
}
return true;
};
// 解数独
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var solveSudoku = function(board) {
backTracking(board);
return board;
};
function backTracking(board) {
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}`
if (backTracking(board)) {
return true;
}
board[i][j] = `.`;
}
}
return false;
}
}
return true;
}
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;
}
}
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;
}