欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

【leetCode】全排列问题,不可重复+可重复

程序员文章站 2022-03-27 20:22:09
思路:回溯算法的方式进行寻找数字,只需要一个arraylist 就可以,不过记住在进行复制的时候及进行深拷贝,不然都是一个引用,呜呜!对于可重复的情况下,要在进行回溯之前进行剪枝,想到这个问题的本质的问题。46. 全排列给定一个 没有重复 数字的序列,返回其所有可能的全排列。示例:输入: [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]47. 全排列 II给定一个可包含重复数字的序列,返回所有不重复的全排列...

思路:回溯算法的方式进行寻找数字,只需要一个arraylist 就可以,不过记住在进行复制的时候及进行深拷贝,不然都是一个引用,呜呜!
对于可重复的情况下,要在进行回溯之前进行剪枝,想到这个问题的本质的问题。

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

47. 全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
【leetCode】全排列问题,不可重复+可重复

第一次写的比较复杂

class Solution {
     public  List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ans=new ArrayList<>();
        List<Integer> single=new ArrayList<>();
        ans= findpermute(ans,nums,single);
        return ans;
    }
    private  List<List<Integer>> findpermute(List<List<Integer>> ans, int[] nums,List<Integer> single) {
        for (int i = 0; i < nums.length; i++) {
            if (! single.contains(i)){
                single.add(i);
                if (single.size()==nums.length){
                    List<Integer> temp= new ArrayList<>();
                    for (int i1 = 0; i1 < single.size(); i1++) {
                        temp.add(nums[single.get(i1)]);
                    }
                    ans.add(temp);
                }else {
                    ans= findpermute(ans, nums,single);
                }
                single.remove(single.indexOf(i));
            }
        }
        return ans;
    }
}

修改之后是这个样子

可以直接使用增强for ,而且直接在方法一开始做判断;最重要的是拷贝的时候直接使用
new ArrayList<>(single)

 public static List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ans=new ArrayList<>();
        findpermute(ans,nums,new ArrayList<>());
        return ans;
    }
    private static  void findpermute(List<List<Integer>> ans, int[] nums,List<Integer> single) {
        if (single.size()==nums.length) ans.add(new ArrayList<>(single));
        for (int num : nums) {
            if (!single.contains(num)) {
                single.add(num);  // 动态维护数组
                findpermute(ans, nums, single); // 继续递归填下一个数
                single.remove((Integer) num);   // 撤销操作,回溯
            }
        }
    }

可重复全排列

第一次自己的想法写的,超时,思考一下有没有什么剪枝的方法
【leetCode】全排列问题,不可重复+可重复

    public static List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> ans=new ArrayList<>();
        findpermuteUnique(ans,nums,new ArrayList<>());
        return ans;
    }
    private static  void findpermuteUnique(List<List<Integer>> ans, int[] nums,List<Integer> single) {
        if (single.size()==nums.length)
        {
            List<Integer> temp=new ArrayList<>();
            for(int i=0;i<single.size();i++) temp.add(nums[single.get(i)]);
            int flag=0;
            for (List<Integer> an : ans){
                flag=0;
                for (int i = 0; i < an.size(); i++) if (an.get(i).equals(temp.get(i))) flag++;
                if (flag==temp.size()) break;
            }
            if (flag!=temp.size()) ans.add(temp);
        }
        for (int i = 0; i < nums.length; i++) {
            if (!single.contains(i)) {
                single.add(i);  // 动态维护数组
                findpermuteUnique(ans, nums, single); // 继续递归填下一个数
                single.remove((Integer) i);   // 撤销操作,回溯
            }
        }
    }

要解决重复问题,我们只要设定一个规则,保证在填第 idx 个数的时候重复数字只会被填入一次即可。而在本题解中,我们选择对原数组排序,保证相同的数字都相邻,然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」,即如下的判断条件:

    if(vis[i] || i>0 && nums[i-1]==nums[i] && vis[i-1]) continue;

这个判断条件保证了对于重复数的集合,一定是从左往右逐个填入的。

假设我们有 33 个重复数排完序后相邻,那么我们一定保证每次都是拿从左往右第一个未被填过的数字,即整个数组的状态其实是保证了 [未填入,未填入,未填入] 到 [填入,未填入,未填入],再到 [填入,填入,未填入],最后到 [填入,填入,填入] 的过程的,因此可以达到去重的目标。

   private static boolean[] vis ;
    public static List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> ans=new ArrayList<>();
        vis=new boolean[nums.length];
        List<Integer> perm=new ArrayList<>();
        Arrays.sort(nums);
        findpermuteUnique(ans,0,nums,perm);
        return ans;
    }

    private static void findpermuteUnique(List<List<Integer>> ans,int idx, int[] nums,List<Integer> perm) {
        if(idx == nums.length){
            ans.add(new ArrayList<>(perm));
        }
        for (int i = 0; i < nums.length; i++) {
            if(vis[i] || i>0 && nums[i-1]==nums[i] && vis[i-1]) continue;
            perm.add(nums[i]);
            vis[i]=true;
            findpermuteUnique(ans,idx+1,nums,perm);
            perm.remove(idx);  //移除的是序号
            vis[i]=false;
        }
    }

本文地址:https://blog.csdn.net/weixin_42462804/article/details/109240284

相关标签: 面试准备