47.全排列Ⅱ
阿新 • • 發佈:2021-06-22
47.全排列Ⅱ
題目
給定一個可包含重複數字的序列 nums ,按任意順序 返回所有不重複的全排列。
示例 1:
輸入:nums = [1,1,2]
輸出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
輸入:nums = [1,2,3]
輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/permutations-ii
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。
題解
輸入的nums是可以包含重複數字的,對排列之後的結果要求是不重複的。
之前處理輸入包含重複,輸出不重複的思路是:對輸入陣列排序是為了方便剪枝掉重複的結果。
通過分別畫出nums無序與有序的圖,發現樹的同一層仍然是不能重複取相同值的,那麼還是需要對輸入陣列進行排序,通過比較前後取值是否一樣來判斷是否取值重複。
對於每一個分支path來說,因為每一次迴圈都是從nums[0]取到最後,那麼已經取過的位置不能再取了。
46題我們使用的是path的路徑之中有就說明已經取值了,沒有就說明還沒有取過值。但這道題nums是可以有值重複的元素,所以設定一個visited陣列記錄元素是否被訪問過。
遞迴的引數和返回值
List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); void backtracing(int [] nums);
回溯的終止條件
全排序是對nums的元素進行排序,那麼排序完path的長度應該等於nums的長度。
if(path.size() == nums.length){
res.add(new ArrayList(path));
return;
}
遞迴的單層邏輯
這裡關於哪些值不可以我其實有點不清楚。重新把抽象樹補充具體了。
同一分支的相同值情況
visited[i-1]==1&&nums[i]==nums[i-1]
說明1#取值的時候1已經取了,那麼當前情況是1#與1在同一分支上,這種情況是允許的。
同一層相同值的情況
visited[i]==0&&nums[i]==nums[i-1]
for(int i=0;i<nums.length;i++){
if(visited[i]==1) continue; //一個分支上的每個位置只能取1次
if(i>0&&visited[i-1]==0&&nums[i]==nums[i-1])continue;
visited[i]=1;
path.add(nums[i]);
backtracing(nums,visited);
visited[i]=0;
path.remove(path.size()-1);
}
程式碼
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path;
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums.length==0) return res;
path = new ArrayList<>();
//如果該陣列只有的取值只有0或1 可以考慮用boolean[] visited = new boolean[nums.length];
int [] visited = new int [nums.length];
Arrays.sort(nums);
backtracing(nums,visited);
return res;
}
void backtracing(int[] nums,int[]visited){
if(path.size() == nums.length){
res.add(new ArrayList(path));
return;
}
for(int i=0;i<nums.length;i++){
if(visited[i]==1) continue;
if(i>0&&visited[i-1]==0&&nums[i]==nums[i-1])continue;
visited[i]=1;
path.add(nums[i]);
backtracing(nums,visited);
visited[i]=0;
path.remove(path.size()-1);
}
}
}
擴充套件
閱讀了大佬的題解,補充一種新思路
對於排列問題,樹層上去重和樹枝上去重,都是可以的,但是樹層上去重效率更高
樹層上去重
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
數枝上去重
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
continue;
}