终止条件
观察思路分析的图,发现剩余集合为空的时候,就是叶子节点。也就是startIndex已经等于数组的长度了,就终止了,因为没有元素可取了,代码如下:
if(startIndex == originalArray.length) {
return;
}
其实可以不需要加终止条件,因为startIndex == originalArray.length
,本层for循环本来也结束了。
遍历顺序
求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树。
代码如下:
for (int i = startIndex; i < originalArray.length; i++) {
path.add(originalArray[i]);
backtracking(path, originalArray, i + 1, result);
path.remove(path.size() - 1);
}
方法二:BFS
Using [1, 2, 3] as an example, the iterative process is like:
-
Initially, one empty subset [[]]
-
Adding 1 to []: [[], [1]];
-
Adding 2 to [] and [1]: [[], [1], [2], [1, 2]];
-
Adding 3 to [], [1], [2] and [1, 2]: [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]].
方法三:位操作
| 十进制 | 二进制 |
| — | — |
| 0 | 000 |
| 1 | 001 |
| 2 | 010 |
| 3 | 011 |
| 4 | 100 |
| 5 | 101 |
| 6 | 110 |
| 7 | 111 |
对例一来说:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
让二进制与无重集合相结合,0表示对应的数不加入集合,1表示对应的数加入集合,如下表:
| - | nums[2]:3 | nums[1]:2 | nums[0]:1 | 子集 |
| — | — | — | — | — |
| 0 | 0 | 0 | 0 | [] |
| 1 | 0 | 0 | 1 | [1] |
| 2 | 0 | 1 | 0 | [2] |
| 3 | 0 | 1 | 1 | [1,2] |
| 4 | 1 | 0 | 0 | [3] |
| 5 | 1 | 0 | 1 | [1,3] |
| 6 | 1 | 1 | 0 | [2,3] |
| 7 | 1 | 1 | 1 | [1,2,3] |
What a happy accident!
参考资料
import java.util.ArrayList;
import java.util.List;
public class Subsets {
// 方法一:回溯算法
public List<List> subsets(int[] nums) {
List<List> result = new ArrayList<>();
List path = new ArrayList<>();
backtracking(path, nums, 0, result);
return result;
}
private void backtracking(List path, int[] originalArray, int startIndex, List<List> result) {
result.add(new ArrayList<>(path));
//本if语块,可以省略
if(startIndex == originalArray.length) {
return;
}
for (int i = startIndex; i < originalArray.length; i++) {
path.add(originalArray[i]);
backtracking(path, originalArray, i + 1, result);
path.remove(path.size() - 1);
}
}
// 方法二:BFS or DP??
public List<List> subsets2(int[] nums) {
List<List> result = new ArrayList<>();
result.add(new ArrayList<>());
for (int i : nums) {
int size = result.size();
for (int j = 0; j < size; j++) {
List temp = new ArrayList<>(result.get(j));
temp.add(i);
result.add(temp);
}
}
return result;
}
// 方法三:位操作
public List<List> subsets3(int[] nums) {
List<List> result = new ArrayList<>();
int total = 1 << nums.length; // 小心溢出
for (int i = 0; i < total; i++) {
List tempList = new ArrayList<>();
for (int j = i, count = 0; j > 0; j >>>= 1, count++) {
if ((j & 1) == 1)
tempList.add(nums[count]);
}
result.add(tempList);
}
return result;
}
}
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.MatcherAssert.assertThat;
import org.hamcrest.Matcher;
import org.junit.BeforeClass;
import org.junit.Test;
@SuppressWarnings(“unchecked”)
public class SubsetsTest {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。
注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
[外链图片转存中…(img-bYy9GNq6-1711789779857)]
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
[外链图片转存中…(img-BL4obge8-1711789779858)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!