力扣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 ...
随机推荐
- 学习Vue.js
Vue.js官网 Vue.js官方教程 Vue.js教程 哔哩哔哩Vue.js教程 Vue.js百度百科
- Docker Swarm:经济高效的容器调度
本文探讨了几种容器调度策略,并以内存约束为例,讨论了如何利用Docker Swarm,通过资源约束实现容器的合理调度.其中,对容器资源的约束,包括硬约束和软约束,硬约束是指内存资源的实际限制条件,而软 ...
- day10-12_线程queue(了解)
queue队列 :使用import queue,用法与进程Queue一样 queue is especially useful in threaded programming when informa ...
- 如何在WPF控件上应用简单的褪色透明效果?
原文 https://dailydotnettips.com/how-to-create-simple-faded-transparent-controls-in-wpf/ 使用OpacityMask ...
- 基本的Sql编写注意事项
基本的Sql编写注意事项 尽量少用IN操作符,基本上所有的IN操作符都可以用EXISTS代替. 不用NOT IN操作符,可以用NOT EXISTS或者外连接+替代. Oracle在执行IN子查询时,首 ...
- Redis源码解析:07压缩列表
压缩列表(ziplist)是列表键和哈希键的底层实现之一.当列表键只包含少量列表项,并且每个列表项要么是小整数值,要么是长度较短的字符串时:或者当哈希键只包含少量键值对,并且每个键值对的键和值要么是小 ...
- 从零学React Native之06flexbox布局
前面我们接触了好多React Native代码, 并没有介绍RN中的组件具体是如何布局的,这一篇文章,重点介绍下flexbox布局. 什么是flexbox布局 React中引入了flexbox概念,f ...
- C++:只用初始化列表初始化变量的几种情况
1.类成员函数中const变量的初始化(也就是第一点) 有几个容易混淆的地方: (1)const 的变量只能通过构造函数的初始化列表进行初始化:(貌似在C++11中可以正常编译) (2)static ...
- 4、安装supervisor
1.安装 sudo apt-get install supervisor 2.如果报phthond2.7错误,则执行 easy_install supervisor 3.配置文件位置和配置文件例子 配 ...
- HTTP协议详解以及URL具体访问过程(转载)
https://blog.csdn.net/f45056231p/article/details/82533490