力扣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 ...
随机推荐
- 【NS2】TCL debug (转载)
1.使用NS2进行模拟,就不可避免的会接触TCL/OTCL和C/C++.两者配合使用.一般设置场景啊,业务流啊,都使用TCL/OTCL来编写脚 本.要进行路由实验模拟的话,同一类的实验,这些脚本基本上 ...
- vue-quill-editor 封装成组件;图片文件流上传;同一页面多个编辑器样式异常解决办法
使用方法: 引入并注册组件,然后直接使用: @getcode是同步获取编辑器内容的::contentDefault是编辑器的默认内容: 注意:如果同一个页面多个编辑器,参数id不能相同,否则只有第一个 ...
- Oracle(ERROR SP2-0642)
阅读目录 报错信息 解决方法 回到顶部 报错信息 ERROR SP2-0642 回到顶部 解决方法 [oracle@oradb]$ sqlplus / as sysdba SP2-0642: SQL* ...
- python 字典元素删减
- CNN如何识别一幅图像中的物体
让我们对卷积神经网络如何工作形成更好直观感受.我们先看下人怎样识别图片,然后再看 CNNs 如何用一个近似的方法来识别图片. 比如说,我们想把下面这张图片识别为金毛巡回犬. 一个需要被识别为金毛巡 ...
- 微信支付、支付宝支付和QQ钱包支付
最近忙于对接微信支付和支付宝支付,注册微信公众号,认证公众号,注册微信支付商户号并进行认证: 签约支付宝支付产品(手机网站支付.PC网站支付),注册支付宝企业账号(企业账号权限更大): 注册QQ钱包商 ...
- uva 12003 Array Transformer (线段树套平衡树)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- 神经网络入门——7or 感知器
OR 感知器 OR 感知器与 AND 感知器很类似,在下图中,OR 感知器与 AND 感知器有相同的分割线,只是 OR 感知器分割线下移了一段距离.对权重或者偏置做怎样的设置可以实现这个效果?用下面的 ...
- python 多线程,tthread模块比较底层,而threading模块是对thread做了一些包装,multithreading
Python多线程详解 2016/05/10 · 基础知识 · 1 评论· 多线程 分享到:20 本文作者: 伯乐在线 - 王海波 .未经作者许可,禁止转载!欢迎加入伯乐在线 专栏作者. 1.多线程的 ...
- JS获取手机型号和系统
废话不多说,直接上源码 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&q ...