題目:
分析:題目進行了改進,多了一個條件,原序列可能包含重複的數字,這個時候再來求所有不重複的全排列。與原序列回溯相比,必定會多一個判定條件用於剪枝,而且這個判定條件一定是用於判定是否重複的,如何思考呢。
先回想一下這個回溯法的過程(步驟),現在假設原序列是不含重複數字的,回溯法就像人工求全排列一樣,先確定第一個位置的數字,然後考慮剩下位置的全排列,然後更換第一個位置的數字再求剩下位置的全排列,那麼原序列有重複的時候,在更換第一個位置數字的時候就有可能出現重複了,那這樣的情況是我們需要避免的,當考慮第一個位置的數字選原序列哪個數字時如果這個數字和前面的有重複那麼說明相同的數字已經在前面考慮過了(作爲第一個位置的數字)這時候應該跳過這個數字的選擇,再往後考慮了。那麼如何記錄哪個數字做過第一個位置的數字呢,可以對原序列進行排序!遍歷原序列的時候,如果當前數字和前一個數字相同則跳過,因爲在當前位置上該數字已經考慮過了
代碼:
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
boolean[] marked = new boolean[nums.length];
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
back(nums, result, path, marked);
return result;
}
static void back(int[] nums, List<List<Integer>> result, List<Integer> path, boolean[] marked){
if(path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
for(int i = 0; i < nums.length; i++){
if(i != 0 && nums[i] == nums[i-1] && marked[i-1] == false){
continue;
}
if(marked[i] == true){
continue;
}
marked[i] = true;
path.add(nums[i]);
back(nums, result, path, marked);
path.remove(path.size()-1);
marked[i] = false;
}
}
}