zoukankan      html  css  js  c++  java
  • 47. Permutations II

    这个比一般的backtrack要难一点,有2个限制因素。

    某个元素在某次递归中只能用一次。

    重复。

    主要就是这2个因素。

    先SORT一下。

    用visited[]记录哪个元素用过,用过直接跳过。

    然后每个递归里,除了第一个元素之外,不许重复。

    if(i != 0 && nums[i] == nums[i-1] && visited[i-1]) continue;
    

    剩下的就是比较基础的backtrack了,记得每次要把visited恢复。

    public class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) 
        {
            List<List<Integer>> res = new ArrayList<List<Integer>>();
            if(nums.length == 0) return res;
            
            Arrays.sort(nums);
            boolean[] visited = new boolean[nums.length];
            
            
            helper(res,nums,new ArrayList<Integer>(),visited);
            
            return res;
        }
        
        public void helper(List<List<Integer>> res, int[] nums, List<Integer> tempList, boolean[] visited)
        {
            if(tempList.size() == nums.length)
            {
                res.add(tempList);
            }
            else
            {
                for(int i = 0; i < nums.length; i++)
                {
                    if(i != 0 && nums[i] == nums[i-1] && visited[i-1]) continue;
                    
                    if(!visited[i])
                    {
                        visited[i] = true;
                        tempList.add(nums[i]);
                        
                        helper(res,nums,new ArrayList<>(tempList),visited);
                        
                        tempList.remove(tempList.size()-1);
                        
                        
                        
                        visited[i] = false;
                    }
                }
                
                
            }
            
        }
    }
    

    这不是重点。。重点是有个用SWAP的方法,46 47都可以那么做。研究一下。。

    public class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) 
        {
            List<List<Integer>> res = new ArrayList<List<Integer>>();
            if(nums.length == 0) return res;
            
            Arrays.sort(nums);
            
            
            
            helper(res,nums,0);
            
            return res;
        }
        
        public void helper(List<List<Integer>> res, int[] nums, int m)
        {
            if(m == nums.length)
            {
                List<Integer> tempList = new ArrayList<>();
                for(int n: nums) tempList.add(n);
                res.add(new ArrayList<>(tempList));
            }
            
            else
            {
                Set<Integer> set = new HashSet<Integer>();
                for(int i = m; i < nums.length;i++)
                {
                    if(set.add(nums[i]))
                    {
                        swap(i,m,nums);
                        helper(res,nums,m+1);
                        swap(i,m,nums);
                    }
                   
                }
            }
            
        }
        
        public void swap(int i,int j,int[] nums)
        {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }
    

    思路是这样的,拿1 2 3。

    先看2 3。 23是一种,交换一下32是一种。
    然后看1,1和2换 后面变成13,又有2种;1和3换,后面是12,又有2种。

    假如前面再有个0,0又要分别和123来换。

    简单地说,每个数都可以在每一个位上来一发。

    这里循环进的M其实是位置,M后面的每个数都可以过来感受一下。。

    很抽象。

    46也可以这么做。



    二刷。

    还是DFS,不过有重复,那重点就是去重了。
    同样深度的情况下,出现重复的,那么需要跳过。 具体说就是:
    判断是否和上一个相等,相等的情况下如果上一个没用过,说明是上一个回溯结束的,同一层,那么就不要再重新来一轮了,跳过。 112 分别以1,1,2开始,第二个1,和第一个1开始的结果重复的。
    在第一个1开始的时候,下一层的当前元素是第二个1,虽然也是1,但是上一个1被用了,说明它是不同深度的,所以不跳过。

    public class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) {
            List<List<Integer>> res = new ArrayList<>();
            boolean[] visited = new boolean[nums.length];
            Arrays.sort(nums);
            dfs(res, visited, nums, new ArrayList<>());
            return res;
        }
        
        public void dfs(List<List<Integer>> res, boolean[] visited, int[] nums, List<Integer> tempList) {
            if (tempList.size() == nums.length) {
                res.add(tempList);
            } else {
                for (int i = 0; i < nums.length; i++) {
                    if (i != 0 && nums[i] == nums[i-1] && !visited[i-1]) continue;
                    if (!visited[i]) {
                        visited[i] = true;
                        tempList.add(nums[i]);
                        dfs(res, visited, nums, new ArrayList<>(tempList));
                        tempList.remove(tempList.size() - 1);
                        visited[i] = false;
                    }    
                }
            }
        }
    }
    
  • 相关阅读:
    关于HTTP协议,一篇就够了
    jvm在什么情况下会执行GC
    为什么我们做分布式使用Redis?
    linux入门系列
    linux学习笔记-13.进程控制
    linux学习笔记-12.输入输出重定向及管道
    app获取自己的签名
    安卓给微信公众号发消息
    微信扫码下载apk
    设备通道开启关闭状态
  • 原文地址:https://www.cnblogs.com/reboot329/p/6053808.html
Copyright © 2011-2022 走看看