递归生成数组子集时全局集合存储空列表的问题咨询
递归生成数组子集时全局集合存储空列表的问题咨询
嗨,我来帮你捋清楚这个问题~你猜的没错,这确实和Java里的引用传递特性直接相关!
咱们来拆解下你代码里的问题根源:
- 你在整个递归过程中只用了一个
ans对象,每次递归传递的都是这个对象的引用,而不是它的副本。 - 当递归走到终止条件
i >= arr.length时,你执行pow.add(ans),这一步只是把ans的引用存到了pow里,并没有把当时ans里的元素复制一份存进去。 - 递归结束后你会执行回溯操作(
ans.remove(ans.size()-1)),等整个递归流程跑完,ans会被一步步回溯成空列表。而pow里的所有元素都是指向同一个ans的引用,所以最后打印pow时,看到的全是空列表;但递归过程中打印ans是当时的实时状态,所以是正确的。
那怎么解决呢?给你两种常用的方案:
方案一:在终止条件中添加ans的副本(推荐,效率更高)
修改终止条件里的代码,每次添加到pow时,新建一个ArrayList来复制当前ans的元素,这样存到pow里的就是独立的列表了:
if(i >= arr.length){ System.out.println(ans); // 仍会打印正确的当前状态 // 新建列表并复制当前ans的元素,再添加到pow pow.add(new ArrayList<>(ans)); return; }
方案二:递归调用时传递ans的副本
这种方式会在每次递归分支时都创建新的列表副本,虽然能解决问题,但因为频繁创建对象,效率不如方案一:
private static void powset(int[] arr, int i, ArrayList<Integer> ans) { if(i >= arr.length){ System.out.println(ans); pow.add(ans); return; } // 包含当前元素的分支:创建新副本添加元素后传递 ArrayList<Integer> includeAns = new ArrayList<>(ans); includeAns.add(arr[i]); powset(arr,i+1,includeAns); // 不包含当前元素的分支:直接传递新副本 ArrayList<Integer> excludeAns = new ArrayList<>(ans); powset(arr,i+1,excludeAns); }
把代码改成方案一的样子,再运行就能看到pow正确输出所有子集啦~
备注:内容来源于stack exchange,提问作者Uddeshya Seth
相关产品推荐
相关产品推荐

