zoukankan      html  css  js  c++  java
  • leetcode 46 全排列(47带重复元素)

    当给定的数组没有重复元素时

    方法一:运用临时的path路径,然后一个标记是否访问的visit[]数组,来进行DFS

    注意java中的一个bug,一个List加到另外一个List里面,前者改变的时候,后者也会改变
     

    方法二: 利用交换的思想,每次都固定前面排好的一部分,直接在给定的数组上面操作,从而省去visit数组和临时path路径

    class Solution {
        public List<List<Integer>> permute(int[] nums) {
            int len = nums.length;
            List<Integer> nnums = new ArrayList<>();
            for(int i:nums){
                nnums.add(i);
            }
            List<List<Integer>> res = new ArrayList<>();
            dfs(nnums,len,0,res);
            return res;
        }
    
        public void dfs(List<Integer> nums,int len,int index,
                        List<List<Integer>> res){
            if(index==len){
                res.add(new ArrayList(nums));
                return;
            }
            for(int i=index;i<len;i++){
                Collections.swap(nums,i,index);
                dfs(nums,len,index+1,res);
                Collections.swap(nums,i,index);
            }
        }
    }
    

    当给定的数组有重复元素时,需要进行剪枝(难点)

     

    • 在图中 ② 处,搜索的数也和上一次一样,但是上一次的 1 还在使用中;
    • 在图中 ① 处,搜索的数也和上一次一样,但是上一次的 1 刚刚被撤销,正是因为刚被撤销,下面的搜索中还会使用到,因此会产生重复,剪掉的就应该是这样的分支。
       

     
    方法一思路图:

    如何理解:

    注意方法一需要排序

    方法一:还是利用临时path路径和visit[]数组,加以判断

     
    在代码中

    • 当一个点访问了时候,就continue
    • 当一个点满足上述的条件(与上一次搜索的数一样且上一个数没有在被使用)
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Deque;
    import java.util.List;
    
    public class Solution {
    
        public List<List<Integer>> permuteUnique(int[] nums) {
            int len = nums.length;
            List<List<Integer>> res = new ArrayList<>();
            if (len == 0) {
                return res;
            }
    
            // 排序(升序或者降序都可以),排序是剪枝的前提
            Arrays.sort(nums);
    
            boolean[] used = new boolean[len];
            // 使用 Deque 是 Java 官方 Stack 类的建议
            Deque<Integer> path = new ArrayDeque<>(len);
            dfs(nums, len, 0, used, path, res);
            return res;
        }
    
        private void dfs(int[] nums, int len, int depth, boolean[] used, Deque<Integer> path, List<List<Integer>> res) {
            if (depth == len) {
                res.add(new ArrayList<>(path));
                return;
            }
    
            for (int i = 0; i < len; ++i) {
                if (used[i]) {
                    continue;
                }
    
                // 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
                // 写 !used[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
                if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
                    continue;
                }
    
                path.addLast(nums[i]);
                used[i] = true;
    
                dfs(nums, len, depth + 1, used, path, res);
                // 回溯部分的代码,和 dfs 之前的代码是对称的
                used[i] = false;
                path.removeLast();
            }
        }
    
        public static void main(String[] args) {
            Solution solution = new Solution();
            int[] nums = {1, 1, 2};
            List<List<Integer>> res = solution.permuteUnique(nums);
            System.out.println(res);
        }
    }
    
    作者:liweiwei1419
    链接:https://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liwe-2/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    

    写 used[i - 1] 代码正确,但是不推荐的原因。https://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liwe-2/
     
    方法二:在原数组上动刀

    //别人的解法
        public List<List<Integer>> permuteUnique(int[] nums) {
            List<List<Integer>> output = new LinkedList<>();
            ArrayList<Integer> nums_list = new ArrayList<>();
            for (int num:nums){
                nums_list.add(num);
            }
            int n = nums.length;
            backTrack(n, nums_list, output, 0);
            return output;
        }
        
        private void backTrack(int n, ArrayList<Integer> nums, List<List<Integer>> output, int first){
            if (first == n){
                output.add(new ArrayList<>(nums));
                return;
            }
            for (int i=first; i<n; i++){
                if (!isRepeat(nums, first, i)){
                    Collections.swap(nums, first, i);
                    backTrack(n, nums, output, first+1);
                    Collections.swap(nums, first, i);
                }
            }
        }
        private boolean isRepeat(ArrayList<Integer> nums, int first, int n){
            int temp = nums.get(n);
            for (int i=first; i<n; i++){
                if (nums.get(i) == temp){
                    return true;
                }
            }
            return false;
        }
    
    作者:cllh1999
    链接:https://leetcode-cn.com/problems/permutations-ii/solution/gai-jin-46guan-fang-ti-jie-qu-zhong-fu-by-cllh1999/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

    思路:
    哪一位可以与后面不相同的换(这个reapeat函数在剑指offer38中可用Hashset实现),就换,形成子路,换了之后就锁住













    种一棵树最好的时间是十年前,其次是现在。
  • 相关阅读:
    构建之法阅读笔记02
    第六周总结
    第四周总结
    课堂练习——数据爬取
    【Spring实战4】02---Spring容器
    【Spring实战4】01---初接触
    性能测试总结(三)--工具选型篇
    性能测试总结(二)---测试流程篇
    性能测试总结(一)---基础理论篇
    接口测试总结【转】
  • 原文地址:https://www.cnblogs.com/islch/p/12813917.html
Copyright © 2011-2022 走看看