代码随想录算法训练营第二十九天/46.全排列、47.全排列2

文章详细阐述了全排列的概念,分别提供了两种全排列的实现:基础全排列和处理重复元素的全排列2。在基础全排列中,通过回溯算法和used数组避免重复。全排列2中,通过对数组排序和树层去重来消除重复的排列。

组合、排列辨析

组合:是无序的,例如:[1,2]、[2,1]是同一个;
排列:是有序的,例如:[1,2]、[2,1]是不一样的。



46.全排列

思路

判断结束条件,当小集合满足长度为原数组长度时,结束;因为全排列就是将数组里面的数组按照不同的顺序进行排列,所以长度是不变的;

因为全排列每次都需要从头开始遍历起,所以参数只要有数组就可以,每次从头开始遍历不需要什么索引来限制;
但是每次遍历时候就会出现重复的,所以使用一个int数组used,给已经使用过的值赋值为1,反之为0;所以在遍历过程中当used数组对应遍历位置值为1时,就跳过当前;之后将符合要求的数据加入到小集合中,要记得给used数组对应位置赋值1,之后进行递归,每次都是从头开始的,接下来进行回溯,要记得将used对应位置赋值等于0。

注意

全排列是每次从头开始遍历,使用used数组,当遍历到之前已经加入到集合中的数据时,利用used的标记来跳过;

实现代码

class Solution {
    List<List<Integer>> res=new ArrayList<List<Integer>>();
    List<Integer> list=new ArrayList<Integer>();
    int [] used;
    public List<List<Integer>> permute(int[] nums) {
        used=new int[nums.length];
        backTracking(nums);
        return res;       
    }
    public void backTracking(int [] nums){
        if(nums.length==list.size()){
            res.add(new ArrayList<>(list));
            return;
        }
        for(int i=0;i<nums.length;i++){
            if(used[i]==1){
                continue;
            }
            list.add(nums[i]);
            used[i]=1;
            backTracking(nums);
            list.remove(list.size()-1);
            used[i]=0;
        }
    }
}

47.全排列2

思路

基本思想是与全排列一样的,唯一不同的是:此题中的数组是存在重复数据的,那么在按照方法得到全部全排列中会有重复的小集合,所以需要利用“树层去重”将重复的去除。

注意

1.注意一个是树层去重,另外一个是全排列的条件;
2.“树层去重”首先要记得给要排列的数据先进行排序。

实现代码

class Solution {
    List<List<Integer>> res=new ArrayList<List<Integer>>();
    List<Integer> list=new ArrayList<Integer>();
    int [] used;
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);
        used=new int[nums.length];
        backTracking(nums);
        return res;
    }
    public void backTracking(int [] nums){
        if(list.size()==nums.length){
            res.add(new ArrayList<Integer>(list));
            return;
        }
        for(int i=0;i<nums.length;i++){
            //树层去重
            if(i>0&&nums[i-1]==nums[i]&&used[i-1]==0||used[i]==1){
                continue;
            }
            list.add(nums[i]);
            used[i]=1;
            backTracking(nums);
            list.remove(list.size()-1);
            used[i]=0; 
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值