版权声明:XiangYida https://blog.csdn.net/qq_36781505/article/details/83583945
90-Subset II
Given a collection of integers that might contain duplicates, nums, return all
possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
这个题目就是说给你一个数组,然后求出他们的子集,最开始以为这个题很简单,思路很快就出来了,但是总是不能Accept,或者我用循环不断的组合然后判断是否重复导致超时。
然后想到了另一种思路
- 1、先排序,排序是很必要的,这样你就知道数组的重复的地方在哪儿了。
- 2、将数组中的数一个一个的放入容器,每放一个,这一个与容器原来的元素组合。
- 3、比较关键的地方就是,重复的数字怎么处理,比如,题目给的1,2,2,我们来模拟一下思路的过程
- 先放入空,此时容器大小为1
- 数组中拿出1,与空相组后放入容器,此时容器的大小为2里面是[[],[1]]
- 数组中拿出2,与空组合后是[2],与[1]组合后是[1,2]此时容器的大小是4,里面的元素是[[],[1],[2],[1,2]]
- 然后是拿出数组的最后一个数2,通过nums[i]==nums[i-1]检测到与上一个数重复了,那是不是不需要这个数去组合了?当然不是,只是不能与上一个2组合过的元素组合,所以我们就记录每次组合后容器的位置index,下次若遇到重复的,就重index位置开始组合就行了。
具体看代码吧,多调试几遍就懂了
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
List<List<Integer>>lists=new LinkedList<>();
lists.add(new LinkedList<>());
int size=lists.size();
//nums[i]数组中的每个元素
int index=0;
for (int i = 0; i <nums.length; i++) {
//与链表中的每个元素相组合
int j=0;
if(i!=0&&nums[i]==nums[i-1])j=index;
for (; j <size; j++) {
List list=new LinkedList(lists.get(j));
list.add(nums[i]);
lists.add(list);
}
index=size;//记录上次的位置
size=lists.size();
}
return lists;
}
这里涉及到一个关键的地方,关于浅拷贝与深拷贝的问题,第二层循环里面若是
List list=lists.get(j);
这样返回的只是地址,也就是你改动的全是一个地址块,这样的话,输出的全是这样
[[1, 2, 2, 2, 2], [1, 2, 2, 2, 2], [1, 2, 2, 2, 2], [1, 2, 2, 2, 2], [1, 2, 2, 2, 2], [1, 2, 2, 2, 2]]
呐~,容器里面每个元素的地址都是一样的呢