目录
46.全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
很明显的递归结构,可以利用递归回溯解决该问题。如下图,解法
(1)使用[1,2,3]构造排列时,可以一次抽出一个元素作为开头
(2)当抽出元素时1的时候,接下来就要对剩余的[2,3]进行构造排列
(3)当抽出元素时2的时候,接下来就要对剩余的[3]进行构造排列,此时因为只有3,所以返回3即可,排列构造完成为123
(4)依次类推,递归回溯,完成问题的解答
class Solution {
private $res = []; //初始化结果数组
private $visited = []; //初始化,记录已访问的元素
private $len;
/**
* @param Integer[] $nums
* @return Integer[][]
*/
function permute($nums) {
$this->len = count($nums);
if($this->len == 0) return $this->res; //当数组为空时,直接返回空
$this->findPermute($nums,0,[]); //递归回溯取得所有结果
return $this->res;
}
/**
* [递归回溯取得全排列]
* @param [type] $nums [问题数组]
* @param [type] $index [下标]
* @param [type] $path [暂存的结果数组]
*/
private function findPermute($nums,$index,$path){
if($index == $this->len){ //当下标到数组长度时,无法继续进行下去,记录结果数组并返回
$this->res[] = $path;
return;
}
for($i = 0;$i<$this->len;++$i){ //依次抽出,进行递归回溯
if($this->visited[$i] == 0){ //压入暂存数组中的元素必须是未访问过的
$path[] = $nums[$i]; //压入暂存数组
$this->visited[$i] = 1; //设置该下标元素已经被访问
$this->findPermute($nums,$index+1,$path); //递归
array_pop($path); //回溯,弹出暂存结果数组,设置元素未访问
$this->visited[$i] = 0;
}
}
}
}
47.全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ]
区别:含有重复数字,最后取得的结果不能重复,所以需要进行一些去重的操作
全排列算法解法就是抽出一个数,然后对剩下的元素再依次抽出递归,因此去重
去重:保证同一层递归中,
(1)必须保证元素未访问过
(2)每次抽出的元素不一样,因为如果抽出的元素一样,则剩余的元素数组也一样,因此先排序数组,可以保证只有相邻的数是可能一样的
class Solution {
private $res = []; //初始化结果数组
private $visited = []; //初始化,记录已访问的元素
private $len,$nums; //初始化问题数组和问题数组的长度
/**
* @param Integer[] $nums
* @return Integer[][]
*/
function permuteUnique($nums) {
$this->len = count($nums);
if($this->len == 0) return $this->res; //当数组为空时,直接返回空
sort($nums); //对问题数组排序,方便之后进行去重
$this->nums = $nums;
$this->findPermute(0,[]); //递归回溯取得所有结果
return $this->res;
}
/**
* [递归回溯取得不重复的全排列]
* @param [type] $index [下标]
* @param [type] $path [暂存的结果数组]
*/
private function findPermute($index,$path){
if($index == $this->len){ //当下标到数组长度时,无法继续进行下去,记录结果数组并返回
$this->res[] = $path;
return;
}
for($i = 0;$i<$this->len;++$i){ //依次抽出,进行递归回溯
//去重:(1)必须保证元素未访问过 (2)每次抽出的元素不一样
if($this->visited[$i] == 1 || ($i>0 && $this->nums[$i] == $this->nums[$i-1] && $this->visited[$i-1] == 0))
continue;
$path[] = $this->nums[$i]; //压入暂存数组
$this->visited[$i] = 1; //设置该下标元素已经被访问
$this->findPermute($index+1,$path);//递归
array_pop($path); //回溯,弹出暂存结果数组,设置元素未访问
$this->visited[$i] = 0;
}
}
}