LeetCode子集问题用subsetArr.size()做循环上限内存溢出原因咨询
问题原因分析
核心原因是:内层循环的判断条件如果直接使用subsetArr.size(),会因为循环体内持续向集合新增元素导致size动态增长,循环永远无法终止,最终耗尽内存触发OOM错误。
逻辑细节说明
生成子集的标准迭代逻辑中,遍历每个数字时,我们只需要基于「处理当前数字前已存在的所有子集」生成新子集:即每个旧子集追加当前数字后加入集合,因此内层循环的遍历次数必须是处理当前数字前的固定集合长度。
你贴出的错误代码中,内层循环每一次迭代前都会重新读取subsetArr.size()的最新值,而循环体内每次执行subsetArr.add(takenList)都会让集合长度+1,最终就会出现无限循环。我们可以用最简单的输入nums = [1]验证执行流程:
- 初始状态
subsetArr = [[]],长度为1 - 遍历到num=1,进入内层循环:
- i=0,判断
0 < 1成立,复制空集追加1得到[1],加入集合后subsetArr长度变为2 - i自增为1,判断
1 < 2成立,复制[1]追加1得到[1,1],加入集合后长度变为3 - i自增为2,判断
2 < 3成立,继续生成新元素加入集合,长度持续增长
- i=0,判断
- 循环永远不会结束,直到JVM堆内存被占满抛出内存溢出错误。
修复方案逻辑
你提到的提前定义int size = subsetArr.size()的方案刚好解决了这个问题:每次处理新数字前先将当前集合长度固定下来,内层循环只遍历固定次数,遍历过程中新增的元素不会被纳入当前轮次的遍历范围,刚好符合子集生成的逻辑,不会出现无限循环。修复后的正确代码如下:
class Solution { public List<List<Integer>> subsets(int[] nums) { List<List<Integer>> subsetArr = new ArrayList<>(); subsetArr.add(new ArrayList<>()); for(int num: nums){ // 提前固定当前轮次需要遍历的集合长度 int size = subsetArr.size(); for(int i=0; i<size; i++){ List<Integer> takenList = new ArrayList<>(subsetArr.get(i)); takenList.add(num); subsetArr.add(takenList); } } return subsetArr; } }
内容的提问来源于stack exchange,提问作者Mukhayyo Tashpulatova
相关产品推荐
相关产品推荐

