LeetCode笔记——46全排列,47全排列Ⅱ

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

借鉴了大神关于排列问题的总结和代码。https://blog.csdn.net/Jacky_chenjp/article/details/66477538?utm_source=copy

示例:

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

思路:

在代码中使用了交换前后元素和DFS(深度优先搜索)的思想。DFS就是一直搜索知道到达搜索结构的叶子节点。我是在和图相关的算法中了解到的这种思想,用途还是挺广的。

代码:

public class Solution {

    // 最终返回的结果集,作为类变量
    List<List<Integer>> res = new ArrayList<List<Integer>>();

    public List<List<Integer>> permute(int[] nums) {
        int len = nums.length;
        if (len==0||nums==null)  return res;

        // 采用前后元素交换的办法,dfs解题
        exchange(nums, 0, len);
        return res;
    }

    public void exchange(int[] nums, int i, int len) {
        // 将当前数组加到结果集中  相当于到达DFS的叶子节点
        if(i==len-1) {
            List<Integer> list = new ArrayList<>();
            for (int j=0; j<len; j++){
                list.add(nums[j]);
            }
            res.add(list);
            return ;
        }
        // 将当前位置的数跟后面的数交换,并搜索解
        for (int j=i; j<len; j++) {
            swap(nums, i, j);
            exchange(nums, i+1, len);
            swap(nums, i, j);
        }
    }

    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

47题目:

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

示例:

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

思路:与46不同的是可以包含重复数字。首先对数组进行排序,将相同的元素放在一起;其次在执行DFS函数时,对于当前元素与前一个元素相同并且当前元素为被添加到list中(即对应的used[]数组为false)时跳过该元素。

整体是递归的思想。将第一个元素放在list的第一个位置,将used设置为true,然后依次对之后的元素调用dfs,知道list的长度和nums长度相同(找到组合);每处理完以一个元素开头的组合就将其设置为false;对于之后相同的元素,由于前一个元素为false,不在list中,所以跳过该元素。

也可以把所有组合的结果当放入set中去除重复的元素(但可能需要的空间比较大吧)

 

代码:

public class Solution {

    List<List<Integer>> res = new ArrayList<List<Integer>>();  //存放最后结果

    public List<List<Integer>> permuteUnique(int[] nums) {
        int len = nums.length;
        if(len==0||nums==null)  return res;

        boolean[] used = new boolean[len];  //用来标记元素,跳过相同元素
        List<Integer> list = new ArrayList<Integer>();  //用来保存每一种组合结果

        Arrays.sort(nums);     //将数组从小到大进行排序
        dfs(nums, used, list, len);
        return res;
    }

    public void dfs(int[] nums, boolean[] used, List<Integer> list, int len) {
        if(list.size()==len) {   //将当前组合添加到结果集中
            res.add(new ArrayList<Integer>(list));
            return ;
        }
        for (int i=0; i<len; i++) {
            // 当前位置的数已经在List中了
            if(used[i]) continue;
            // 当前元素与其前一个元素值相同 且 前元素未被加到list中,跳过该元素
            if(i>0 && nums[i]==nums[i-1] && !used[i-1])   continue;
            // 深度优先搜索遍历
            used[i]=true;
            list.add(nums[i]);
            dfs(nums, used, list, len);
            list.remove(list.size()-1);
            used[i]=false;
        }
    }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值