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;
                    }    
                }
            }
        }
    }
    
  • 相关阅读:
    Attributes in C#
    asp.net C# 时间格式大全
    UVA 10518 How Many Calls?
    UVA 10303 How Many Trees?
    UVA 991 Safe Salutations
    UVA 10862 Connect the Cable Wires
    UVA 10417 Gift Exchanging
    UVA 10229 Modular Fibonacci
    UVA 10079 Pizza Cutting
    UVA 10334 Ray Through Glasses
  • 原文地址:https://www.cnblogs.com/reboot329/p/6053808.html
Copyright © 2011-2022 走看看