题目描述
题目分析
感觉这道题让自己对枚举排列有了一个更好的认识,感觉自己的这种思路不错。
假设没有重复元素(退化成78.子集),我们应该怎么做?初始的时候幂集中只有一个空集,然后对每个元素,我们添加给幂集中的每个元素,这样进行一遍遍历,复杂度是 O ( 1 ) + O ( 2 ) + O ( 4 ) + . . . + O ( 2 n − 1 ) = O ( 2 n ) O(1)+O(2)+O(4)+...+O(2^{n-1})=O(2^n) O(1)+O(2)+O(4)+...+O(2n−1)=O(2n)
对于有重复元素的我们应该如何处理呢?不难发现,假设我们把重复元素放在一起,则对于第一个元素是没有什么影响的,但是对第二个元素开始,我们对幂集最前面集合添加元素和前面的那个元素没有区别,因此就会出现重复,从哪里开始不一样呢?从前一个元素开始添加的部分开始,因此我们用一个变量记录前一个元素开始添加的位置,然后从重复元素的第二个开始都从前一个元素添加的开始位置开始添加,最后更新这个变量。可以再对照代码理解一下,代码比较简单
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
ans.push_back(vector<int>());
ans.push_back(vector<int>());
ans.back().push_back(nums[0]);
int n = nums.size();
int pre_i = 1; //保存上次添加后的起始地址
for(int i = 1; i < n; ++i) {
int m = ans.size();
int j = 0;
if (nums[i] == nums[i - 1]) {
//如果和上一个数字一样,则从上一个数字开始的地方开始,因为前面的已经由上一个数字处理过了
j = pre_i;
}
for (; j < m; ++j) {
auto t = ans[j];
t.push_back(nums[i]);
ans.push_back(t);
}
pre_i = m; //更新per_i
}
return ans;
}
};
吐槽
觉得子集的思路比题解的要清晰,复杂度应该也低很多,我这个应该是 O ( 2 n ) O(2^n) O(2n),不知道为什么题解的那么复杂,要枚举二进制或者用回溯。
这个执行用时有点玄学的,可能只测试了部分样例吧,毕竟是企业,少测试一会就可以多赚钱,可以理解。我觉得leetcode还是比较适合用来学习算法和数据结构的,感觉写官方题解的人的水平也不一样,有的题解思路清晰,代码巧妙,能从代码中看出写这个代码的人造诣很高,对语言的理解也很深刻,但是今天的这个题解我就觉得不怎么样,子集那道题的题解我也觉得不怎么样,复杂度感觉都求错了。