全排列(去除重复)Permutations II
為什么80%的碼農都做不了架構師?>>> ??
問題:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2]?have the following unique permutations:
解決:
①?與Permutations類似,因為包含重復的數字,所以我們要對重復的排列序列進行排除,首先我們對數組進行排序,判斷當前遍歷到的數是否與前一個數相同,使用一個標記數組boolean[] used來判斷前一個相同的值是否被使用了,若正在被使用,說明正在處于前一個值得遞歸過程中,當前值不能被跳過;若沒有被使用,說明這個值已經作為頭部被使用過了,跳過當前值以排除重復。使用一個鏈表pre來記錄之前排列好的值,需要注意的是,遍歷完成一個排列之后,需要還原pre以進行下一次排列。
public class Solution { //7ms
? ? public List<List<Integer>> permuteUnique(int[] nums) { ??
? ? ? ? List<List<Integer>> res = new ArrayList<List<Integer>>();
? ? ? ? if(nums == null || nums.length == 0) return res;
? ? ? ? boolean [] used = new boolean[nums.length];
? ? ? ? List<Integer> pre = new ArrayList<>();
? ? ? ? Arrays.sort(nums);
? ? ? ? dfs(nums,used,pre, res);
? ? ? ? return res;
? ? }
? ? private void dfs(int[] nums, boolean [] used, List<Integer> pre, List<List<Integer>> res){
? ? ? ? if(pre.size() == nums.length){
? ? ? ? ? ? res.add(new ArrayList<>(pre));//若直接res.add(pre),會導致集合為空[[],[],[],[],[],[]]
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? for(int i = 0; i < nums.length; i ++){
? ? ? ? ? ? if(i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;//去重
? ? ? ? ? ? if(! used[i]){
? ? ? ? ? ? ? ? used[i] = true;
? ? ? ? ? ? ? ? pre.add(nums[i]);//加入當前值
? ? ? ? ? ? ? ? dfs(nums,used,pre,res);//遞歸查找值
? ? ? ? ? ? ? ? pre.remove(pre.size() - 1);//還原前一個排列,繼續查找排列
? ? ? ? ? ? ? ? used[i] = false;
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
② 另外,我們可以使用一個臨時鏈表cur來記錄加入當前值之后的排列,這樣,就可以避免還原pre。
public class Solution { //11ms
? ? List<List<Integer>> res = new ArrayList<>();
? ? public List<List<Integer>> permuteUnique(int[] nums) {
? ? ? ? int len = nums.length;
? ? ? ? if(len == 0) return res;
? ? ? ? Arrays.sort(nums);
? ? ? ? boolean[] used = new boolean[len];
? ? ? ? List<Integer> pre = new ArrayList<>();
? ? ? ? dfs(nums,used,pre);
? ? ? ? return res;
? ? }
? ? private void dfs(int[] nums,boolean[] used,List<Integer> pre){
? ? ? ? if(pre.size() == nums.length){//完成一個排列
? ? ? ? ? ? //res.add(new ArrayList<Integer>(pre));
? ? ? ? ? ? res.add(pre);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? for(int i = 0;i < nums.length;i ++){
? ? ? ? ? ? if(i > 0 && nums[i] == nums[i - 1] && ! used[i - 1]) continue;//前一個數沒有被選中,說明在前一個數時已經完成了以該數為開頭的排列
? ? ? ? ? ? List<Integer> cur = new ArrayList<Integer>(pre);//這樣就不需要還原pre了,因為pre與cur分開了
? ? ? ? ? ? if(! used[i]){
? ? ? ? ? ? ? ? cur.add(nums[i]);
? ? ? ? ? ? ? ? used[i] = true;
? ? ? ? ? ? ? ? dfs(nums,used,cur);
? ? ? ? ? ? ? ? used[i] = false;
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
③ 直接使用backtrack(DFS)而不用使用標記位。并且不需要對數組排序。以{1,1,2}為例進行遞歸分析如下:
class Solution { //6ms
????public List<List<Integer>> permuteUnique(int[] nums) {
????????List<List<Integer>> res = new ArrayList<>();
????????dfs(nums,0,res);
????????return res;
????}
????public void dfs(int[] nums,int i,List<List<Integer>> res){//i表示當前排列的開頭在原固定數組中的位置
????????//找到轉換完成的鏈表,將其存入鏈表中
????????if(i == nums.length - 1){//遞歸結束條件,得到一個排列
????????????List<Integer> tmp = new ArrayList<>();
????????????for (int j = 0;j < nums.length ;j ++ ) {
????????????????tmp.add(nums[j]);
????????????}
????????????res.add(tmp);
????????}else{//沒有完成排列
????????????for (int j = i;j < nums.length ;j ++ ){//排列i之后的數
????????????????if(containsRepeated(nums,i,j)) continue;//判斷i到j之間是否存在重復,如果存在,則不需要交換和遞歸,因為這是同一個排列??
? ? ? ? ? ? ? ? //若不存在重復,則進行以下排列??????????????
? ? ? ? ? ? ? ? swap(nums,i,j); //交換開頭,若j=i表示固定當前開頭計算排列,否則表示以當前值為開頭的已經排列完了
????????????????dfs(nums,i + 1,res);//改變數組的開頭為原數組中i之后的第一個數,遞歸得到它的全排列
????????????????swap(nums,i,j);//遞歸完成,還原交換的數組
????????????}
????????}
????}
????public boolean containsRepeated(int[] nums,int i,int j){
????????for (int k = i;k <= j - 1 ;k ++ ) {//若i=j,則無法進入該循環,直接返回false;
????????????if(nums[k] == nums[j]) return true;
????????}
????????return false;
????}
????public void swap(int[] nums,int i,int j){
????????int tmp = nums[i];
????????nums[i] = nums[j];
????????nums[j] = tmp;
????}
}
轉載于:https://my.oschina.net/liyurong/blog/1528741
總結
以上是生活随笔為你收集整理的全排列(去除重复)Permutations II的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Outlook式样界面菜单和页面控制
- 下一篇: 【nginx】关于Nginx的一些优化(