经典题目,
跟LC78不一样的地方在于 (LC78见另外外一篇博文 https://www.jianshu.com/p/3b8fd52774f7)
这里有重复,需要去重。
LC78 版本二的解法关键在于不要回头看。这次要去重,要求就又苛刻些。
这次关键在于不仅不能回头看,如果你错过风景了,遇到相同的风景也不再收入囊中了。
先来的元素有优先权,如果你遇到一对完全相同的元素,双胞胎,如果你没取第一个却取了第二个,是不是就重复了? 所以你要么取第一个, 要么取第一个和第二个,要么哪个也不取,你不能只取第二个,这两个元素有尊卑。其实元素本身没有尊卑,但为了去重我们故意给他们按照先来后到的顺序标了优先级。
另外外一种理解方法是每一层只能取该层多胞胎中的第一个。
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(nums);
subsetsWithDup(nums, 0, ans, new ArrayList<>());
return ans;
}
private void subsetsWithDup(int[] nums, int index,
List<List<Integer>> ans, List<Integer> curList ) {
ans.add(new ArrayList<>(curList));
for (int i = index; i < nums.length; i++) {
if (i != index && nums[i] == nums[i - 1]) continue; //去重的关键在于此行
curList.add(nums[i]);
subsetsWithDup(nums, i + 1, ans, curList);
curList.remove(curList.size() - 1);
}
}
C++版本
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
vector<int> cur;
dfs(nums, ans, 0, cur);
return ans;
}
private:
void dfs(const vector<int>& nums, vector<vector<int>>& ans, int index, vector<int>& cur) {
ans.emplace_back(cur);
if (index == nums.size()) return;
for (int i = index; i < nums.size(); i++) {
if (i != index && nums[i] == nums[i - 1]) continue;
cur.push_back(nums[i]);
dfs(nums, ans, i + 1, cur);
cur.pop_back();
}
}
};
注意请轻易不要使用class variable。
这题我尝试使用 https://www.jianshu.com/p/3b8fd52774f7 的第一个版本基础上增加去重功能, 发现比较麻烦,做倒是可以做。
假设你有5个5,就是要数一数已经取过的5和见过的5是不是数量相等。如果不相等,主不要取5了, 如果相等可以取5,也可以不取5,这个比较麻烦,不容易写的漂亮。