为什么我们要在一些递归算法中复制ArrayList?

时间:2013-12-23 06:25:12

标签: java algorithm arraylist

http://oj.leetcode.com/problems/subsets-ii/

给定可能包含重复项的整数集合S,返回所有可能的子集。

注意:

* Elements in a subset must be in non-descending order.
* The solution set must not contain duplicate subsets.

例如, 如果S = [1,2,2],则解决方案是:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

答案是:

public class Solution {
   public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] num) {
       ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
       ArrayList<Integer> tmp = new ArrayList<Integer>();
       Arrays.sort(num);
       sub(num, 0, tmp, ans);
       return ans;        
   }

   public void sub(int[] num, int k, ArrayList<Integer> tmp, ArrayList<ArrayList<Integer>> ans) {
       ArrayList<Integer> arr = new ArrayList<Integer>(tmp);            
       ans.add(arr);       

       for (int i = k; i < num.length; i++) {
           if (i != k && num[i] == num[i-1]) continue;

           tmp.add(num[i]);
           sub(num, i+1, tmp, ans);
           tmp.remove(tmp.size()-1);
       }
   }
}

我不知道为什么

 ArrayList<Integer> arr = new ArrayList<Integer>(tmp);            
 ans.add(arr);

但不是直接:

 ans.add(tmp);

3 个答案:

答案 0 :(得分:2)

直接添加它将使arr包含/与tmp相同的ArrayList实例。在你的循环中,当你改变tmp时,你也会改变arr,这不是你想要的程序。

答案 1 :(得分:2)

如果您只想打印出结果,因为删除了在递归调用后添加的任何元素,tmp在函数的开头和结尾都应该看起来完全一样,所以它不应该' t会有所不同(因为它不会在每一步都复制ArrayList,所以你会喜欢你的方式。)

但是当您将结果添加到ans时会出现问题。

如果您按照自己的方式使用,只会有一个ArrayList浮动 - 您只需将其多次添加到ans

请注意,将其添加到ans实际上并不创建它的副本,只是添加了对ArrayListans的引用。因此,在添加原始文件后更改原始文件也会更改ans的元素。

Live demo showing the correct result by printing them out and the incorrect results in the returned array

答案 2 :(得分:1)

不使用

的原因
 ans.add(tmp);

由于tmp是一个方法参数,因此java按值传递对ArrayList的引用。 所以tmp实际上是对List的引用,而不是List。

因此,您需要创建一个ArrayList对象,并将该对象添加到ans

ArrayList<Integer> arr = new ArrayList<Integer>(tmp);            
ans.add(arr);   

如果你使用ans.add(tmp),那么tmp指向的arrayList将被添加到ans中,如果稍后在代码中对tmp进行了任何修改,那么你的元素的内容添加到ans也会更改,因为两者都会指向相同的内存块