給定一個(gè)可能包含重復(fù)元素的整數(shù)數(shù)組 nums,返回該數(shù)組所有可能的子集(冪集)让网。
說(shuō)明:解集不能包含重復(fù)的子集。
示例:
輸入: [1,2,2]
輸出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
來(lái)源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/subsets-ii
解題思路
采用深度優(yōu)先搜索
dfs(int[] nums, int start, Deque<Integer> path, List<List<Integer>> result)
參數(shù)依次是數(shù)組萝映,起始拼接位置鳄炉,搜索過(guò)程中的路徑,結(jié)果集
因?yàn)椴荒艹霈F(xiàn)重復(fù)元素烟勋,比如[1, 2, 2]這個(gè)集合规求,會(huì)出現(xiàn)兩個(gè)[1, 2]
這時(shí)要考慮"剪枝",剪枝的前提是將數(shù)組排序
然后考慮剪枝的條件"同一層不能用相同數(shù)字"
比如[1, 2, 2]深度優(yōu)先遍歷時(shí)
image.png
在代碼中如何呈現(xiàn)卵惦?
在關(guān)鍵方法 dfs() 中阻肿,for 循環(huán)代表了同一層,而遞歸代表了不同層
所以在 for 循環(huán)中要判斷索引 i 是否為起始索引沮尿,不是起始索引且和前一個(gè)元素相同則剪枝
代碼
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new LinkedList<>();
if (nums == null || nums.length == 0) {
return result;
}
result.add(new ArrayList<>()); // 空集
Arrays.sort(nums);
Deque<Integer> path = new LinkedList<>();
dfs(nums, 0, path, result);
return result;
}
private void dfs(int[] nums, int start, Deque<Integer> path, List<List<Integer>> result) {
for (int i = start; i < nums.length; i++) {
if (i == start || nums[i] != nums[i - 1]) {
path.addLast(nums[i]);
result.add(new ArrayList<>(path));
dfs(nums, i + 1, path, result);
path.removeLast();
}
}
}
}