1. 程式人生 > >LeeCode 39 組合總和(天坑啊java的值傳遞,頭都被打懵了)

LeeCode 39 組合總和(天坑啊java的值傳遞,頭都被打懵了)

給定一個無重複元素的陣列 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和為 target 的組合。

candidates 中的數字可以無限制重複被選取。

說明:

  • 所有數字(包括 target)都是正整數。
  • 解集不能包含重複的組合。 

示例 1:

輸入: candidates = [2,3,6,7], target = 7,
所求解集為:
[
  [7],
  [2,2,3]
]

示例 2:

輸入: candidates = [2,3,5], target = 8,
所求解集為:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

啊,此題真是,一言難盡啊,先上報錯程式碼(因為一直找不到錯誤,還以為邏輯錯了,就把C/C++的正確程式碼重寫了一遍,沒想到還是一直報錯,最後靈機一動,想到值傳遞這件事,才AC程式碼):

package LeetCode;
import java.util.*;

public class Lee_39_SumOfZuHe {
	public static void main(String[] args){
		int[] candidates = new int[]{2,3,6,7};
		int target = 7;
		new Lee_39_SumOfZuHe().combinationSum(candidates,target);
	}
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
    	List<List<Integer>> list = new ArrayList<List<Integer>>();
   	
     	List<Integer> mylist = new ArrayList<Integer>();;
    	Arrays.sort(candidates);
    	//System.out.println(Arrays.toString(candidates));
    	ReccombinationSum(candidates,target,0,mylist,list);
    	//System.out.print(list);
    	return list;
    }
    public void ReccombinationSum(int[] Newcandidates,int sum,int start,List<Integer> mylist,List<List<Integer>> list){
        if(sum<0)
    		return;
        else if(sum==0){
    		list.add(mylist);
    		return;
    	}
    	else{
    		for(int i=start;i<Newcandidates.length;i++){
    			int current = Newcandidates[i];
    			mylist.add((Integer)current);
    			ReccombinationSum(Newcandidates,sum-current,i,mylist,list);	//主要是此行程式碼
    			mylist.remove((Integer)current);
    		}
    	}
    }
}

結果跑出了空結果:

加了一行檢測程式碼,發現能跑出正確結果,說明只是list沒能真正新增元素:

那麼問題出在哪呢?難受啊兄die~~~

後面理解了值傳遞,改了程式碼:

    			ReccombinationSum(Newcandidates,sum-current,i,mylist,list);		
    			ReccombinationSum(Newcandidates,sum-current,i,new ArrayList<Integer>(mylist),list);		

可以看見,主要是在遞迴過程中重新建立了物件,其實理解了java的值傳遞模式就能理解了,當mylist作為形參進行傳遞時,傳遞的是mylist的地址值,當然可以通過對mylist的地址值對物件進行操作,然而如果不重新new一個mylist出來,在進行list.add(mylist)的時候,只會把這一個物件進行add,然而再往後遞迴的時候,由於mylist是一個物件,mylist先add後remove自然會將mylist清空,而list真正add的其實是mylist的地址,add了兩次其實是add了mylist這一個物件兩次,然後mylist又被清空,所以結果只能是[ [ ] , [ ] ],更改程式碼後,結果AC~~~

話說回來,博主之前也做過類似的遞迴題,不過由於用的不是list這樣通過地址值傳遞的遞迴,而是利用String 進行遞迴,沒出現問題,現在想來,String作為不可變數,每次更改時其實都是重新申請了String物件,暗合值傳遞理念,只能說博主還是太年輕啊~~引以為鑑!