力扣90——子集 II
原题
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
原题url:https://leetcode-cn.com/problems/subsets-ii/
解题
递归
这道题,针对已经刷了不少题目的我们而言,应该第一想到的就是递归了,从第1个数开始,每次遍历1个数,如果和之前的数相同则跳过,然后以下一个数为起点,继续遍历。让我们来看看代码:
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
// 从小到大排序
Arrays.sort(nums);
// 最终结果
List<List<Integer>> result = new LinkedList<>();
result.add(new LinkedList<>());
// 回溯
dfs(0, nums, new Stack<>(), result);
return result;
}
public void dfs(int index, int[] nums, Stack<Integer> stack, List<List<Integer>> result) {
if (index >= nums.length) {
return;
}
for (int i = index; i < nums.length; i++) {
// 在这一次总的查找中,如果当前节点和上一个节点相同,则跳过
if (i > index && nums[i] == nums[i - 1]) {
continue;
}
// 添加该数
stack.push(nums[i]);
// 作为一种情况,放进结果中
result.add(new LinkedList<>(stack));
// 继续回溯
dfs(i + 1, nums, stack, result);
// 回退
stack.pop();
}
}
}
提交OK,执行用时:2 ms,内存消耗:36.5 MB,但执行用时只战胜40.16%,那就来优化一下。
优化
看了第一眼,我真的不知道该如何优化。我先是想到将递归改成迭代,但感觉并没有从时间上做出优化,不过还是给大家看一下:
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
if (nums == null || nums.length == 0) {
return new LinkedList<>();
}
// 从小到大排序
Arrays.sort(nums);
// 最终结果
List<List<Integer>> result = new ArrayList<>(1 << nums.length);
result.add(0, new LinkedList<>());
// 上一步新解的开始下标
int newStartIndex = 1;
// 遍历添加
for (int i = 0; i < nums.length; i++) {
int j = 0;
// 和上一个数字相同,则只针对上一步的新解增加
if (i > 0 && nums[i] == nums[i - 1]) {
j = newStartIndex;
}
int length = result.size();
newStartIndex = length;
for (;j < length; j++) {
List<Integer> tempList = result.get(j);
List<Integer> newList = new LinkedList<>(tempList);
newList.add(nums[i]);
result.add(newList);
}
}
return result;
}
}
提交之后,果然不出所料,和之前一样,那就再让我们想想。
还记得在之前文章中曾经说过,new LinkedList<>(Collection<? extends E> c)其内部依旧是遍历,很耗性能。因此我专门看了一下new ArrayList<>(Collection<? extends E> c),其内部最终会调用Systemp.arraycopy。让我们再试一次:
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
// 从小到大排序
Arrays.sort(nums);
// 最终结果
List<List<Integer>> result = new LinkedList<>();
result.add(new ArrayList<>());
// 回溯
dfs(0, nums, new Stack<>(), result);
return result;
}
public void dfs(int index, int[] nums, Stack<Integer> stack, List<List<Integer>> result) {
if (index >= nums.length) {
return;
}
for (int i = index; i < nums.length; i++) {
// 在这一次总的查找中,如果当前节点和上一个节点相同,则跳过
if (i > index && nums[i] == nums[i - 1]) {
continue;
}
// 添加该数
stack.push(nums[i]);
// 作为一种情况,放进结果中
result.add(new ArrayList<>(stack));
// 继续回溯
dfs(i + 1, nums, stack, result);
// 回退
stack.pop();
}
}
}
提交之后,果然OK了,执行用时:1 ms,战胜100%的 java 提交记录。
我这里再说明一下,LinkedList 的遍历拷贝,每个元素都需要重新计算内存位置,而 ArrayList 的拷贝,可以直接一次性申请一大片空间,写入和遍历的速度会更快。
总结
以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题目只要利用递归就可以解决了,但优化的时候,需要注意数据结构(是不是我之前用一些的 LinkedList 换成 ArrayList 会效果更好呢)。
有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。
公众号:健程之道


力扣90——子集 II的更多相关文章
- 90. 子集 II
90. 子集 II 题意 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2]输出:[ [2], [1], ...
- Leetcode之回溯法专题-90. 子集 II(Subsets II)
Leetcode之回溯法专题-90. 子集 II(Subsets II) 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入 ...
- Java实现 LeetCode 90 子集 II(二)
90. 子集 II 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1], [ ...
- [leetcode] 90. 子集 II.md
90. 子集 II 78. 子集题的扩展,其中的元素可能会出现重复了 我们仍沿用78题的代码,稍作改动即可: 此时需要对nums先排个序,方便我们后面跳过选取相同的子集. 跳过选取相同的子集.当选取完 ...
- 刷题-力扣-213. 打家劫舍 II
213. 打家劫舍 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/house-robber-ii/ 著作权归领扣网络所有.商业 ...
- leetcode刷题-90子集 II
题目 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2]输出:[ [2], [1], [1,2,2], [ ...
- leetcode 90. 子集 II JAVA
题目: 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1], [1,2,2] ...
- Leetcode 90. 子集 II
地址 https://leetcode-cn.com/problems/subsets-ii/ 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重 ...
- LeetCode 90. 子集 II(Subsets II)
题目描述 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1], [1,2,2 ...
随机推荐
- ES6对象的super关键字
super是es6新出的关键字,它既可以当作函数使用,也可以当作对象使用,两种使用方法不尽相同 1.super用作函数使用的时候,代表父类的构造函数,es6规定在子类中使用this之前必须先执行一次s ...
- Win7中右下角“小喇叭”声音图标消失的解决方法?(已解决)
Win7中右下角"小喇叭"声音图标消失的解决方法?(已解决) 1.打开任务管理器. 2.右键explorer.exe选择右键结束. 3.在按ctrl+shift+Esc,或者用al ...
- SQL注入原理讲解,很不错!
SQL注入原理讲解,很不错! 原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html 1.1.1 摘要 日前,国内最大的程序员 ...
- @atcoder - Japanese Student Championship 2019 Qualification - F@ Candy Retribution
目录 @description@ @solution@ @accepted code@ @details@ @description@ 请找到满足以下条件的长度为 N 的非负整数序列 A1, A2, ...
- PHP怎么调用其他类的方法
2个PHP,这个PHP中的类调用另一个PHP中的类,如何调用.Java中是import ,php中是什么?还是用其他什么方法? 1.引用类:比如类名为product,则:include('...路径/ ...
- mysql数据库之linux版本
http://repo.mysql.com/yum/mysql-5.6-community/ 安装 ...
- Uniapp使用iconfont
看别人的项目有各种各样的图标既好看占用内存还小 后来才知道原来有icon图标这个东西,原谅我真的一直处于混沌的状态. 刚好最近项目使用了uniapp框架,引入iconfont的方式和之前有些不太一样 ...
- oracle避免在索引列上使用NOT
通常, 我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的 影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描. 举例: 低效: (这里,不使用索引) S ...
- 使用php函数ini_set()重新设置某个配置的设置值
使用PHP的ini_set()函数 ini_set (PHP 4, PHP 5, PHP 7) ini_set — 为一个配置选项设置值 说明 string ini_set ( string $var ...
- Django使用cors解决跨域问题
1.安装Django-cors-headers模块 pip install django-cors-headers 2.配置settings.py文件 INSTALLED_APPS = [ ... ' ...