全排列
没有重复的全排列
关键点
- visited 数组,标记某个元素是否使用过
- 每次都是从 i = 0 开始搜索
- 无需设置start 索引
- 可以使用变量depth 表示当前遍历到的层数,满足n层后加到结果集即可。
class Solution {
/**
* @param Integer[] $nums
* @return Integer[][]
*/
protected $res46 = [];
function permute($nums) {
$n = count($nums);
$visited = array_fill(0, $n, 0);
$this->help46($nums, [], 0, $n, $visited);
return $this->res46;
}
protected function help46(&$nums, $path, $depth, $n, &$visited) {
if ($depth == $n) {
$this->res46[] = $path;
return;
}
for ($i = 0; $i < $n; $i++) {
if ($visited[$i]) {
continue;
}
$visited[$i] = 1;
$path[] = $nums[$i];
$this->help46($nums, $path, $depth + 1, $n, $visited);
$visited[$i] = 0;
array_pop($path);
}
}
}
全排列ii
带有重复数字的全排列
关键点
- 因为还是全排列,所以排列该有的used数组还得有
- 因为有重复要去重,所以先排序
- 去重关键。去重的时候不仅需要比较当前数和前面数一样不一样,还得考虑前面的数用过没有。不然有重复的时候无法得到解集。看到一个好的解释
if ($i > 0 && $nums[$i] == $nums[$i-1] && $used[$i-1] === 0)continue;
// 这里理解used[i - 1]非常重要。
// used[i - 1] == true,说明同一树支nums[i - 1]使用过
// used[i - 1] == false,说明同一树层nums[i - 1]使用过
// 如果同一树层nums[i - 1]使用过则直接跳过
//而且一般同层去重效率会高一些。
作者:carlsun-2
链接:https://leetcode-cn.com/problems/permutations-ii/solution/47-quan-pai-lie-iiche-di-li-jie-pai-lie-zhong-de-q/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
/**
* @param Integer[] $nums
* @return Integer[][]
*/
public $resPermuteUnique = [];
function permuteUnique($nums) {
$n = count($nums);
$used = [];
sort($nums);
$this->helpPermuteUnique($nums, $used, [], $n, 0);
return $this->resPermuteUnique;
}
protected function helpPermuteUnique ($nums, &$used, $temp, $n, $depth) {
if ($depth == $n) {
$this->resPermuteUnique[] = $temp;
return;
}
for ($i = 0; $i < count($nums); $i++) {
if ($used[$i])continue;
if ($i > 0 && $nums[$i] == $nums[$i-1] && $used[$i-1] === 0)continue;
$used[$i] = 1;
$temp[] = $nums[$i];
$this->helpPermuteUnique($nums, $used, $temp, $n, $depth+1);
array_pop($temp);
$used[$i] = 0;
}
return;
}
}
子集
无重复数字的子集
关键点
- 子集系列有start 开始搜索位置了。
- 到下一层的时候因为当前元素不再可选,所以i+1
子集ii
有重复数数字的子集
关键点
- 有重复就排序
- 去重的时候比较的是i>start的时候有没有重复,而不是i>0