前言
食用前,若了解递归、树的基本结构及前中后序遍历,风味更佳~
概述
回溯算法
- 走不通就退回再走
- 虚拟设置N叉树,不需要构造一棵真正的树结构
- 递归调用前:每走到一个分支,做出选择后剪除该分支,记录该选择进行下一层分支的深度遍历;
- 递归调用后:回到上一层决策树时,把该选择及结果恢复
递归
- 自己调用自己
- 利用函数的入栈出栈特性,并在入栈出栈前后不断重复搞事情
代码
// 回溯算法解全排列问题(排列数字唯一不重复版)
function backtrack(&$globalSelectList, &$res, $thisSelectList, $thisRes)
{
// 记录当前深度遍历完成后的结果
if (count($globalSelectList) == count($thisRes)) {
$res[] = $thisRes;
}
foreach ($thisSelectList as $k => $v) {
// 记录到当前深度遍历的结果
if (!in_array($v, $thisRes)) {
$thisRes[] = $v;
}
// echo 'before::', json_encode([$k, $v, $thisSelectList, $thisRes]), '; '; // 可输出帮助理解
// 剪枝(在当前决策树该选择已做过,往下深度遍历前删掉该选择)
unset($thisSelectList[$k]);
backtrack($globalSelectList, $res, $thisSelectList, $thisRes);
// 深度遍历后回到上一层决策树时,把该选择及结果恢复
$thisSelectList[$k] = $v;
array_pop($thisRes);
// echo 'after::', json_encode([$k, $v, $thisSelectList, $thisRes]), '; '; // 可输出帮助理解
}
}
$globalSelectList = range(1, 3);
$res = [];
$thisSelectList = $globalSelectList;
$thisRes = [];
backtrack($globalSelectList, $res, $thisSelectList, $thisRes);
// echo 'resCount:', count($res), ';res:', json_encode($res);
// resCount:6;res:[[1,2,3],[1,3,2],[2,3,1],[2,1,3],[3,1,2],[3,2,1]]
建议
建议将递归调用前后的情况输出看看,可帮助加深理解
参考
- 公众号labuladong学算法
- https://blog.csdn.net/gardenpalace/article/details/84625537