【PHP解法==LeetCode(回溯递归2-排列)】46.全排列 && 47.全排列 II

目录

46.全排列

47.全排列 II


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;
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值