回溯法和動態規劃輕鬆解決Combination Sum IV問題

 

目錄

 

一、回溯法簡介    

二、動態規劃簡介

三、題目

四、實現

1、思路

2、遞歸求解

3、遞歸代碼+dp

五、總結


一、回溯法簡介
    

      回溯法(探索與回溯法)是一種選優搜索法,又稱爲試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。回溯法很有趣可以解決一系列的問題,比如子集問題、排列問題以及八皇后問題等。是個很值得研究和學習的算法。可以細看我之前的博客https://blog.csdn.net/kupepoem/article/details/106662487和https://blog.csdn.net/kupepoem/article/details/106665698

二、動態規劃簡介

        動態規劃程序設計是對解最優化問題的一種途徑、一種方法,而不是一種特殊算法。不像搜索或數值計算那樣,具有一個標準的數學表達式和明確清晰的解題方法。動態規劃程序設計往往是針對一種最優化問題,由於各種問題的性質不同,確定最優解的條件也互不相同,因而動態規劃的設計方法對不同的問題,有各具特色的解題方法,而不存在一種萬能的動態規劃算法,可以解決各類最優化問題。因此讀者在學習時,除了要對基本概念和方法正確理解外,必須具體問題具體分析處理,以豐富的想象力去建立模型,用創造性的技巧去求解。我們也可以通過對若干有代表性的問題的動態規劃算法進行分析、討論,逐漸學會並掌握這一設計方法。 可以參看我之前的博文。

三、題目

來源:https://leetcode-cn.com/problems/combination-sum-iv

給定一個由正整數組成且不存在重複數字的數組,找出和爲給定目標正整數的組合的個數。

示例:

nums = [1, 2, 3]
target = 4

所有可能的組合爲:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

請注意,順序不同的序列被視作不同的組合。

因此輸出爲 7。

 

四、實現

1、思路

    這和Combination Sum1-3比較類似,沿用Combination Sum即可。沿用Combination Sum思路你會發現計算會超時,因爲枝幹實在是太多。那麼加入dp記錄下一些中間結果,進一步的進行剪枝。

2、回溯法遞歸

        下面的回溯法遞歸代碼是會超時的。

int combinationSum_help2(vector<int>& candidates,int resval ,std::vector<int> &dp)
{


		if (resval == 0)
		{
			
		   return 1;//剪枝
		}
		else if(resval<0)
		{
		   return 0;//剪枝
		}


       
		int sumres=0;


		for (int i = 0; i < candidates.size(); ++i)
		{

		   sumres+=combinationSum_help2(candidates, resval - candidates[i],dp);
 
		}
		dp[resval]=sumres;
		return sumres;
 
		}


int combinationSum4(vector<int>& nums, int target) 
{
		int res=0;
		std::vector<int> dp;
		dp.resize(target+1);
		for(int i=0;i<target+1;i++)
		  dp[i]=-1;
		int sum=combinationSum_help2(nums, target,dp);
		return sum;

}

3、回溯法遞歸+dp

int combinationSum_help2(vector<int>& candidates,int resval ,std::vector<int> &dp)
{


		if (resval == 0)
		{
			
		   return 1;//剪枝
		}
		else if(resval<0)
		{
		   return 0;//剪枝
		}


		if(dp[resval]!=-1)
		  return dp[resval];//剪枝
		int sumres=0;
		for (int i = 0; i < candidates.size(); ++i)
		{

		   sumres+=combinationSum_help2(candidates, resval - candidates[i],dp);
 
		}
		dp[resval]=sumres;
		return sumres;
 
	}

int combinationSum4(vector<int>& nums, int target)
{
		int res=0;
		std::vector<int> dp;
		dp.resize(target+1);
		for(int i=0;i<target+1;i++)
		  dp[i]=-1;
		int sum=combinationSum_help2(nums, target,dp);
		return sum;


}

五、總結

     算法設計還是要掌握其中的思想,掌握了思想問題也就迎刃而解了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章