回溯法輕鬆解決Combination Sum問題

一、回溯法簡介

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

二、題目

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

給定一個無重複元素的數組 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]
]

三、實戰

1、思路

   求所有的解是回溯法的強項,暴力進行回溯也是可以求解的只是時間效率肯定是比較低的,那麼如何剪枝呢

a、定義一個resval resval爲殘差值 這樣我們可以在resval==0時記錄結果並剪枝,resval<0時候剪枝

b、排序 這樣我們可以一直往前找

2、實現

	void combinationSum_help(vector<int>& candidates,int start, vector<int> &resdfs, vector<vector<int>> &res,int resval)
	{
		if (resval == 0)
		{
			res.push_back(resdfs);
			return;//剪枝
		}
		else if(resval<0)
		{
			return;//剪枝
		}

		for (int i = start; i < candidates.size(); ++i)
		{
			resdfs.push_back(candidates[i]);
			combinationSum_help(candidates, i, resdfs, res, resval - candidates[i]);
			resdfs.pop_back();

		}

	}

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> res;
		vector<int> resdfs;
		std::sort(candidates.begin(), candidates.end(), [](int a, int b) {
			return a < b;
		});

		combinationSum_help(candidates, 0, resdfs, res, target);
        return res;
        
    }

 

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