描述
給定一個可能具有重復數字的列表,返回其所有可能的子集
注意事項
子集中的每個元素都是非降序的
兩個子集間的順序是無關緊要的
解集中不能包含重復子集
樣例
如果 S = [1,2,2],一個可能的答案為
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
挑戰
你可以同時用遞歸與非遞歸的方式解決么?
代碼
class Solution {
/**
* @param nums: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {
ArrayList<ArrayList<Integer>> results = new ArrayList<>();
if (nums == null || nums.length == 0) {
return results;
}
Arrays.sort(nums);
ArrayList<Integer> subset = new ArrayList<Integer>();
subsetWithDupHelper(nums, 0, subset, results);
return results;
}
private void subsetWithDupHelper(int[] nums,
int startIndex,
ArrayList<Integer> subset,
ArrayList<ArrayList<Integer>> results) {
results.add(new ArrayList<Integer>(subset));
for (int i = startIndex; i < nums.length; i++) {
/* 本來初值是令i = startIndex,正常運行代碼不應該出現取第二個不取
* 第一個的情況,但此條if本身就是用于表示異常的,所以一切就變得
* 可以理解了
*/
if (i != 0 && nums[i] == nums[i - 1] && i > startIndex){
/* i != 0是為了防止 i - 1越界,
* nums[i] = nums[i - 1] 即當前數等于前一個數,
* 從下面 subset 兩行代碼可以看出如果 nums[i - 1] 被加入 subset,
* 那么下一個startIndex = i - 1 + 1 = i;
* i > startIndex等價于i >= startIndex + 1,而上一個數是startIndex - 1;
* 說明在startIndex - 1和startIndex + 1間存在一個數,
* 存在當前值nums的前一個與它相等的值并沒有被添加到list里,這樣會重復
*/
continue;
}
subset.add(nums[i]);
subsetWithDupHelper(nums, i + 1, subset, results);
subset.remove(subset.size() - 1);
}
}
}
本題和subset相比就多了一個去重的過程,去重的邏輯已經在注釋里說清楚了,稍微補充點就是比如數組是[1,2,2],第一個2用A表示,第二個2用B表示,我們要的順序是[1,A],此時的要去的重就是[1,B]這種組合,比較容易混淆的是[1,A,B]這種情況A,B兩個2在同一個list里并不算重復,去除的是兩個list之間的重復情況