思路1:建立二叉树 + 回溯(左孩子选,右孩子不选)
- 本质上是一颗二叉树,对于数组中的每个数字而言,可以被选择,也可以不被选择。走左边就是被选择,走右边就是不被选择。
- 如何确保一个数字可以重复被选择,下一层遍历的时候,依然从当前下标
index开始,而不是从index + 1开始,backtrace(ans, res, target - candidates[index], candidates, index) - 剪枝条件是什么?
target == 0 - 如何进行回溯?
res.pop_back()
代码1:
void backtrace(vector<vector<int>>& ans, vector<int>& res, int target, vector<int>& candidates, int index) { if (index == candidates.size()) { return; } if (target == 0) { ans.push_back(res); return; } // 不选当前位置 backtrace(ans, res, target, candidates, index + 1); // 选择当前位置 if (target - candidates[index] >= 0) { res.push_back(candidates[index]); backtrace(ans, res, target - candidates[index], candidates, index); // 回溯 res.pop_back(); } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { vector<vector<int>> ans; vector<int> res; backtrace(ans, res, target, candidates, 0); return ans; }
思路2:叶子节点是数组最后一个元素
- 和思路一本质上是一棵树,但是对形状进行优化
- 剪枝条件不变
- 通过遍历数组的方式建树,下一轮循环的开始不是
cur_subscript + 1,而是cur_subscript(因为当前数字可以被用很多次)
代码2:
void backtrace(vector<vector<int>>& ans, vector<int>& path_res, int target, vector<int>& candidates, int cur_subscript) { int all_candidates = candidates.size(); if (cur_subscript == all_candidates || target < 0) { return; } if (target == 0) { ans.push_back(path_res); return; } // 按照数组来建立树 for (int i = cur_subscript; i < all_candidates; i++) { path_res.push_back(candidates[i]); backtrace(ans, path_res, target - candidates[i], candidates, i); path_res.pop_back(); } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { vector<vector<int>> ans; vector<int> path_res; backtrace(ans, path_res, target, candidates, 0); return ans; }