刷題494. Target Sum

一、題目說明

題目494. Target Sum,給定一列非負整數,一個目標數S,給定每個數一個+,-號,計算有多少組合可以生成S的值。難度是Medium!

二、我的解答

最直接的方案就是對每一個數num[i],可以正,可以負,通過遞歸就可以枚舉所有情況。

class Solution{
	public:
		//recursive
		int findTargetSumWays(vector<int>& nums,int S){
			dfs(nums,0,0,S);		
			return count;
		}
		void dfs(vector<int>& nums,int i,int sum,int S){
			if(i==nums.size()){
				if(sum == S){
					count++;
				}
			}else{
				dfs(nums,i+1,sum+nums[i],S);
				dfs(nums,i+1,sum-nums[i],S);
			}
		}
	private:
		int count = 0;
};

性能如下:

Runtime: 1084 ms, faster than 20.25% of C++ online submissions for Target Sum.
Memory Usage: 8.6 MB, less than 61.54% of C++ online submissions for Target Sum.

三、優化措施

dp[i][j] 表示用數組中的前 i 個元素,組成和爲 j 的方案數。dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]]

用P表示所有正數的和,用N表示所有負數的和,用T表示目標和,用All表示整個集合的和:

P-N = T    --->    N = P-T
P+N=All   --->    P+(P-T) = 2P-T = ALL
P = (T+ All)/2   總和All已知,T已知,求P即可,這是一個典型的揹包問題。

問題轉換爲:存在一個容量爲P 的揹包,從 nums 中任意抽取一定數量的數,使得揹包恰好被放滿,有多少种放法。

class Solution{
	public:
		//dp  P = (T+ All)/2
		int findTargetSumWays(vector<int>& nums,int S){
			long sum = 0;
			for(auto it:nums){
				sum += it;
			}
			if((S+sum)%2==1 || S>sum){
				return 0;
			}
			S = (S+sum)/2;
			vector<int> dp(S+1,0);
			dp[0] = 1;
			for(const int & it:nums){
				for(int j=S;j>=it;j--){
					dp[j] += dp[j-it];
				}
			}
			return dp[S];
		}
};

性能如下:

Runtime: 4 ms, faster than 97.66% of C++ online submissions for Target Sum.
Memory Usage: 8.8 MB, less than 46.15% of C++ online submissions for Target Sum.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章