zoukankan      html  css  js  c++  java
  • 全排列(力扣第46题)

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

    示例:

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

    分析:

      求给定一组数的全排列,也就是排列组合问题,所以属于Backtracking(回溯)问题,通过DFS解决,只不过需要注意的是,我们一般使用DFS的时候都会设置一个访问标记的数组,用于保证深度递归的过程中,某一个元素不会被重复访问,但是由于现在我们要求的是排列组合问题,所以我们要尽可能的把所有的解求出来,那么只要一条递归路径中有一个元素不同,那就是不用的递归路径,所以当我们从一个元素递归返回的时候,要将此元素对应于访问标记数组中的值复位,保证从其他路径路过此元素时,能够正常的访问。

      其实对于一组数来说,假设一共有n个数,那么这n个数全排列的结果是n!个,其具体的计算结果是 n * (n-1) * ……* 2 * 1 。我们可以将这个计算过程想象成我们使用DFS搜索时进行搜索的过程,比如最开始的时候,我们从哪个元素最先开始搜索,此时一共有n个数未被访问,那么就有n种选择;然后继续搜索,那么还剩n-1个数未被访问,此时可选择走的方向就有n-1个选择;……,以此类推,就是求所有的排列的过程。每到一个元素,进行的下一步走向的选择,就是通过for循环实现,保证所有的可能都要经历。

    代码实现:

        private List<List<Integer>> reslist;
    
        public List<List<Integer>> permute(int[] nums) {
    
    
            if (nums.length == 0 || nums == null){
                return new ArrayList<>();
            }
            int n = nums.length;
            boolean[] isVisited = new boolean[n];
            reslist = new ArrayList<List<Integer>>();
            List<Integer> sortres = new ArrayList<>();
            for (int i = 0; i < nums.length; i++) {
    
                findAllSort(nums,i,isVisited,sortres);
            }
            return reslist;
        }
    
        private void findAllSort(int[] nums, int i, boolean[] isVisited, List<Integer> sortres) {
    
            if (isVisited[i]){
                return;
            }
    
            isVisited[i] = true;
            sortres.add(nums[i]);
    
            if (sortres.size() == nums.length){
                reslist.add(new ArrayList<>(sortres));
                isVisited[i] = false;
                sortres.remove(sortres.size()-1);
                return;
            }
    
            for (int i1 = 0; i1 < isVisited.length; i1++) {
    
                if (!isVisited[i1]){
                    findAllSort(nums,i1,isVisited,sortres);
                }
            }
    
            isVisited[i] = false;
            sortres.remove(sortres.size()-1);
        }

    记住,当遍历完一条路径的时候,给此路径添加到结果列表,需要新建一个list对象,然后将sortres结果传进去,直接将sortres添加到结果列表中是不行的,因为当我们再一次修改sortlist时,原先存于结果列表的内容也会被修改。

    上面是我自己实现的代码,然后也参考了cyc2018的代码,他的代码比我的性能要好一些,但是我俩的做法思想基本是一样的:

    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> permutes = new ArrayList<>();
        List<Integer> permuteList = new ArrayList<>();
        boolean[] hasVisited = new boolean[nums.length];
        backtracking(permuteList, permutes, hasVisited, nums);
        return permutes;
    }
    
    private void backtracking(List<Integer> permuteList, List<List<Integer>> permutes, boolean[] visited, final int[] nums) {
        if (permuteList.size() == nums.length) {
            permutes.add(new ArrayList<>(permuteList)); // 重新构造一个 List
            return;
        }
        for (int i = 0; i < visited.length; i++) {
            if (visited[i]) {
                continue;
            }
            visited[i] = true;
            permuteList.add(nums[i]);
            backtracking(permuteList, permutes, visited, nums);
            permuteList.remove(permuteList.size() - 1);
            visited[i] = false;
        }
    }

    参考:cyc2018

  • 相关阅读:
    【逻辑漏洞技巧拓展】————4、逻辑漏洞之支付漏洞
    【逻辑漏洞技巧拓展】————3、逻辑漏洞之密码重置
    【逻辑漏洞技巧拓展】————2、Web安全测试中常见逻辑漏洞解析(实战篇)
    【逻辑漏洞技巧拓展】————1、逻辑至上之各种酷炫姿势
    【文件上传/解析技巧拓展】————4、文件上传总结
    【文件上传/解析技巧拓展】————3、服务器解析漏洞
    【文件上传/解析技巧拓展】————2、文件上传漏洞(绕过姿势)
    window 杀进程
    URL的三部分
    基本的浏览器连接处理步骤
  • 原文地址:https://www.cnblogs.com/yxym2016/p/13251964.html
Copyright © 2011-2022 走看看