12、全排列(medium)

1.题目描述:

2.题目描述:

给定一个不含重复数字的数组nums,返回其所有可能的全排列。可以按照任意顺序返回答案。

       示例 1:​
                                     输入:nums = [1,2,3]​
                                     输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]​
       示例 2:​
                                     输入:nums = [0,1]​
                                     输出:[[0,1],[1,0]]​
       示例 3:​
                                     输入:nums = [1]​
                                     输出:[[1]]​
       提示:
                                     1 <= nums.length <= 6​
                                     -10 <= nums[i] <= 10​
                                     nums 中的所有整数 互不相同​

3. 解法:
算法思路:

典型的回溯题目,我们需要在每一个位置上考虑所有的可能情况并且不能出现重复。通过深度优先搜索的方式,不断地枚举每个数在当前位置的可能性,并回溯到上一个状态,直到枚举完所有可能性,得到正确的结果。

每个数是否可以放入当前位置,只需要判断这个数在之前是否出现即可。具体地,在这道题目中,我们可以通过一个递归函数 backtrack 和标记数组 visited 来实现全排列。​

递归函数设计:void backtrack(vector<vector<int>>& res, vector<int>& nums, vector<bool>& visited, vector<int>& ans, int step, int len)​
参数:step(当前需要填入的位置),len(数组长度);​
返回值:无;
函数作用:查找所有合理的排列并存储在答案列表中。

递归流程如下:
1. 首先定义一个二维数组 res 用来存放所有可能的排列,一个一维数组 ans 用来存放每个状态的排列,一个一维数组 visited 标记元素,然后从第一个位置开始进行递归;​
2. 在每个递归的状态中,我们维护一个步数 step,表示当前已经处理了几个数字;​
3. 递归结束条件:当 step 等于 nums 数组的长度时,说明我们已经处理完了所有数字,将当前数组存入结果中;
4. 在每个递归状态中,枚举所有下标 i,若这个下标未被标记,则使用 nums 数组中当前下标的元 素:
         a. 将 visited[i] 标记为 1;​
         b. ans 数组中第 step 个元素被 nums[i] 覆盖;​
         c. 对第 step+1 个位置进行递归;​
         d. 将 visited[i] 重新赋值为 0,表示回溯;​
5. 最后,返回 res。​
特别地,我们可以不使用标记数组,直接遍历 step 之后的元素(未被使用),然后将其与需要递 归的位置进行交换即可。

Java算法代码:

class Solution {

        List<List<Integer>> ret;
        List<Integer> path;
        boolean[] check;

    public List<List<Integer>> permute(int[] nums) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        check = new boolean[nums.length];
        dfs(nums);
        return ret;
    }
    public void dfs(int nums[]) {
        if(nums.length == path.size()){
            ret.add(new ArrayList<>(path));
            return ;
        }
        for(int i = 0;i< nums.length ;i++){
            if(check[i] == false) {
                path.add(nums[i])       ;
                check[i] = true;
                dfs(nums);
                //回溯 ->恢复现场
                check[i] = false;
                path.remove(path.size()-1);
            }
        }
    }
}

执行结果:

递归展开:

注意这里笔者并没有展开完,而是只展开了一次循环(还差两次),强烈建议读者自己来展开。或者是简化[1,2],但是需注意,[1,2]展开可能并不是那么的好(使得你很好的理解)。

逻辑展开:

请注意,前面的递归题目,都在灌输的思想是,相信你的递归函数!

从这里题目开始,读者应该发现,题目难度直线上升,现在要开始关注递归函数的实现。

---------------------------------------------------------------------------------------------------------------------------------

记住,相信你的递归函数,它可以做到!

记住,不理解时候,去尝试手动展开!

记住,逻辑展开(你不可能对所有的题目都进行手动展开)!

记住,理解递归函数!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值