關於深淺拷貝的一個小坑
前言
從 c++ 轉到 java,對於 java 的基礎一直不好。今天想刷幾個題鞏固一下基礎,於是開心的刷起了 leetcode …
果然,不一會兒就掉坑裏了…
心路歷程
題目到是不難,就求給定集合的子集,二進制枚舉和深搜都能做。
啪啪啪敲完,完全是 c++ 風格 …
怎麼看都是對的,結果是所有子集都長一個模樣…
搞了半天,問題出在了淺拷貝上:
/*
tmp 是 List<Integer>,保存着當前的子集
ans 是 List< List<Integer> >,所有子集的集合
要把 tmp 傳進去的時候,直接傳引用的話,
會導致 ans 保存的引用全是一樣的,所以必須深拷貝一個新的對象。
*/
ans.add(tmp); //淺拷貝傳入引用出錯。
ans.add(new ArrayList<Integer>(tmp)); //深拷貝,正確
題解
public class Solution {
private List<List<Integer>> dfs(int dep, int[] a, List<Integer> tmp, List<List<Integer>> ans){
if(dep == a.length){
//ans.add(tmp); //淺拷貝傳入引用出錯。
ans.add(new ArrayList<Integer>(tmp)); //深拷貝
}else{
dfs(dep+1, a, tmp, ans);
tmp.add(a[dep]);
dfs(dep+1, a, tmp, ans);
tmp.remove(tmp.size()-1);
}
return ans;
}
public List<List<Integer>> subsets(int[] nums) {
Arrays.sort(nums);
return dfs(0, nums, new ArrayList<Integer>(), new ArrayList<List<Integer>>());
}
}
總結
java 的 ArrayList 和 c++ 的 vector 還是有區別的。
ArrayList 的 add 是淺拷貝,只保存了對象的引用。
vector 的 push_back 是深拷貝,傳入的時候 new 了一個新的對象。