目录
- 1.组合
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 2.目标和
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 3.组合总和
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
1.组合
1.题目链接
- 组合
2.算法原理详解
- 思路:每次都只选一个数,此后只能选它后面的数
- 函数设计:
- 全局变量:
vector<vector<int>> ret
vector<int> path
DFS()
设计:void DFS(nums, pos)
- 递归出口:
path.size() == k
- 剪枝:控制参数,每次从此位置下一个位置开始递归
- 全局变量:
3.代码实现
class Solution
{int _n;int _k;vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> combine(int n, int k) {_n = n;_k = k;DFS(1);return ret;}void DFS(int start){if(path.size() == _k){ret.push_back(path);}// 递归 + 剪枝for(int i = start; i <= _n; i++){path.push_back(i);DFS(i + 1);path.pop_back(); // 回溯,恢复现场}}
};
2.目标和
1.题目链接
- 目标和
2.算法原理详解
- 本题与子集逻辑几乎相同
- 本题会实现两种代码,可以通过这两种代码来感受:回溯的两种做法
path
是全局变量的时候- 本题可能会超时
path
作为参数- 此时编译器/代码会代为回溯,每次回溯都省去了一次加/减运算,故效率有所提高
- 此时编译器/代码会代为回溯,每次回溯都省去了一次加/减运算,故效率有所提高
3.代码实现
// v1.0 效率低,可能会超时
class Solution
{int ret = 0;int path = 0;int _target = 0;
public:int findTargetSumWays(vector<int>& nums, int target) {_target = target;DFS(nums, 0);return ret;}void DFS(vector<int>& nums, int pos){if(pos == nums.size()){if(path == _target){ret++;}return;}// 加path += nums[pos];DFS(nums, pos + 1);path -= nums[pos]; // 回溯,恢复现场// 减path -= nums[pos];DFS(nums, pos + 1);path += nums[pos]; // 回溯,恢复现场}
};
--------------------------------------------------------------------------
// v2.0,效率有所改善
class Solution
{int ret = 0;int _target = 0;
public:int findTargetSumWays(vector<int>& nums, int target) {_target = target;DFS(nums, 0, 0);return ret;}void DFS(vector<int>& nums, int pos, int path){if(pos == nums.size()){if(path == _target){ret++;}return;}// 加DFS(nums, pos + 1, path + nums[pos]);// 减DFS(nums, pos + 1, path - nums[pos]);}
};
3.组合总和
1.题目链接
- 组合总和
2.算法原理详解
-
思路一:每次都只选一个数,此后只能选它及它后面的数
- 函数设计:
- 全局变量:
vector<vector<int>> ret
vector<int> path
DFS()
设计:void DFS(nums, pos, sum)
- 递归出口:
sum == _target || (sum > _target || pos == nums.size())
- 回溯:通过
sum
控制回溯 - 剪枝:控制
pos
参数,每次从此位置开始递归
- 全局变量:
- 函数设计:
-
思路二:每次枚举一个数,出现几次
- 函数设计:
- 全局变量:
vector<vector<int>> ret
vector<int> path
DFS()
设计:void DFS(nums, pos, sum)
- 递归出口:
sum == _target || (sum > _target || pos == nums.size())
- 回溯:通过
sum
控制回溯 - 剪枝:控制
pos
参数,每次从此位置开始递归
- 全局变量:
- 函数设计:
3.代码实现
// v1.0 每次都只选一个数,此后只能选它及它后面的数
class Solution
{int _target;vector<int> path;vector<vector<int>> ret;
public:vector<vector<int>> combinationSum(vector<int>& nums, int target) {_target = target;DFS(nums, 0, 0);return ret;}void DFS(vector<int>& nums, int pos, int sum){if(sum == _target){ret.push_back(path);return;}if(sum > _target || pos == nums.size()){return;}// 递归决策 + 剪枝for(int i = pos; i < nums.size(); i++){path.push_back(nums[i]);DFS(nums, i, sum + nums[i]);path.pop_back(); // 回溯,恢复现场}}
};
--------------------------------------------------------------------------
// v2.0 每次枚举一个数,出现几次
class Solution
{int _target;vector<int> path;vector<vector<int>> ret;
public:vector<vector<int>> combinationSum(vector<int>& nums, int target) {_target = target;DFS(nums, 0, 0);return ret;}void DFS(vector<int>& nums, int pos, int sum){if(sum == _target){ret.push_back(path);return;}if(sum > _target || pos == nums.size()){return;}// 枚举个数 + 剪枝for(int i = 0; i * nums[pos] + sum <= _target; i++){if(i){path.push_back(nums[pos]); }DFS(nums, pos + 1, i * nums[pos] + sum);}// 回溯,恢复现场for(int i = 1; i * nums[pos] + sum <= _target; i++){path.pop_back();}}
};