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;
                }    
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM