这道题是第78题的升级版,78题中所给数组的元素都是不相同的,所以直接回溯搞一发,每个元素都加或不加搞一发即可。然而这道题中元素可能是相同的,所以不能直接每个元素加或不加来搞。比如样例中的[1, 2, 2],只加前面的那个2和只加后面那个2的结果是重复的,所以需要对相同的数进行判断。
在78题中,一个长为l的数组,子集list的第一个元素可以是数组中的每一个元素,第二个元素就是第一个元素的索引之后的数组中的每一个元素,以此类推。解法如下:
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
output = []
l = len(nums)
def backtrack(begin: int, cur: List[int]):
output.append(cur[:])
for i in range(begin, l):
cur.append(nums[i])
backtrack(i+1, cur)
cur.pop()
backtrack(0, [])
return output
而在本题中,第二个元素不能是第一个元素索引之后的数组的每一个元素,因为后面的元素有重复,所以如果取每一个元素的话,解会重复。所以第二个元素应该是后面的数组中不重复的元素(例:如果后面的元素是4,5,4,5,6,5,那么第二个元素可能为4,5,6),为了更好的得到这些不重复的元素,可以先将数组进行排序,这样重复的数字就会排在一起,取每个重复串的第一个元素即可得到后面的数组中不重复的元素。想到这里之后,将78题的代码改一下即可。答案如下:
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
l = len(nums)
nums.sort()
result = []
tmp = []
def backtrack(ind: int):
result.append(tmp[:])
for i in range(ind, l):
if i != ind and nums[i] == nums[i-1]:
continue
tmp.append(nums[i])
backtrack(i+1)
tmp.pop()
backtrack(0)
return result
以上代码的c++实现如下:
class Solution {
vector<vector<int>> result;
public:
void dfs(vector<int>& nums, int ind, vector<int> tmp) {
result.push_back(tmp);
if(ind >= nums.size()) {
return;
}
for(int i = ind; i < nums.size(); i++) {
if(i != ind && nums[i] == nums[i-1]) {
continue;
}
tmp.push_back(nums[i]);
dfs(nums, i+1, tmp);
tmp.pop_back();
}
return;
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
result.clear();
sort(nums.begin(), nums.end());
vector<int> tmp;
tmp.clear();
dfs(nums, 0, tmp);
return result;
}
};
我发现我不会写C++了,这不对劲,之后还是偶尔用c++搞一搞吧。
本文详细介绍了LeetCode第90题Subsets II的解题方法,重点在于处理重复元素的问题。在原始问题的基础上,通过排序数组并选择每个重复元素串的第一个元素来避免重复子集。文章提供了C++代码实现,并分享了作者对于C++编程的个人感悟。

275

被折叠的 条评论
为什么被折叠?



