2017-02-24 60 views
3

當我試圖解決子問題,我寫這樣的代碼:ArrayList中,列表

public class Subsets { 
     public List<List<Integer>> subsets(int[] nums) { 
      List<List<Integer>> list = new ArrayList<>(); 
      Arrays.sort(nums); 
      backtrack(list, new ArrayList<>(), nums, 0); 
      return list; 
     } 
     public void backtrack(List<List<Integer>> list, ArrayList<Integer>temp, int[] nums, int start){ 
      list.add(temp); 
      for(int i = start; i<nums.length;i++){ 
       temp.add(nums[i]); 
       backtrack(list, temp, nums, i++); 
       temp.remove(temp.size()-1); 
      }   
     } 
    } 

輸出是

[[] [] [] [] ,[],[],[],[]]

但正確的答案應該是

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

當我改變「回溯」這樣的代碼,得到的答案是正確的:

public void backtrack(List<List<Integer>> list, List<Integer> temp, int[] nums, int start){ 
    list.add(new ArrayList(temp)); 
    for(int i = start; i<nums.length;i++){ 
    temp.add(nums[i]); 
    backtrack(list, temp, nums, i+1); 
    temp.remove(temp.size()-1); 
    } 
} 

我的問題:爲什麼我需要寫這樣的代碼:

public void backtrack(List<List<Integer>> list, List<Integer> temp, int[] nums, int start){ 
     list.add(new ArrayList(temp)); 

的而不是:

public void backtrack(List<List<Integer>> list, ArrayList<Integer> temp, int[] nums, int start){ 
     list.add(temp); 
+0

非常感謝您的快速接受。我很高興它爲你工作! – GhostCat

回答

2

^h ERE:

list.add(new ArrayList(temp)); 

,創建一個新的名單對象,用temp時間點的內容。

list.add(temp); 

只是增加了現有temp清單list參考。

因此,在第二種情況下,當您修改temp那也影響list的內容。

但除此之外:你的代碼很難閱讀/理解,因爲它應該是。有沒有指向該方法使用temp參數。例如,您可以在方法內部使temp爲局部變量。無論如何,傳入列表是。將此作爲輸入參數不會使您獲得任何收益;你只會添加混淆。

然後你提高你的命名 - 爲listtemp確實沒有給讀者什麼打算用法這些變量的是說話。

0

list.add(temp)將對列表添加對同一個temp對象的引用。之後,您將從中移除元素直到它爲空,並且算法以包含對同一個空列表的多個引用的列表結束。

使用new ArrayList(temp)(或更好 - 類型安全new ArrayList<>(temp))將創建具有相同內容temp一個新的列表,所以後來,當您從temp刪除元素,這個列表不會受到影響。