Leetcode 回溯题目合辑 PHP

242 阅读1分钟

全排列

没有重复的全排列

关键点

  • 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