【算法训练营day27】LeetCode39. 组合总和 LeetCode40. 组合总和II LeetCode131. 分割回文串
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
LeetCode39. 组合总和
题目链接:39. 组合总和
独上高楼,望尽天涯
题目不难,注意start_index参数的使用。
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int start_index) {
if (target == 0) {
result.push_back(path);
return;
}
else if (target < 0) {
return;
}
for (int i = start_index; i < candidates.size(); i++) {
target -= candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, i); //不用i+1,因为可以无限重复选取
target += candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates, target, 0);
return result;
}
};
慕然回首,灯火阑珊
和题解想的一样。
剪枝操作
在求和问题中,排序之后加剪枝是常见的套路。
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int start_index) {
if (target == 0) {
result.push_back(path);
return;
}
for (int i = start_index; i < candidates.size() && target - candidates[i] >= 0; i++) { // 剪枝操作
target -= candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, i);
target += candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end()); // 需要排序
backtracking(candidates, target, 0);
return result;
}
};
LeetCode40. 组合总和II
题目链接:40. 组合总和II
独上高楼,望尽天涯
本题的难点在于去重,建议回溯问题以后都要在纸上画出清晰的递归树形结构,会对解题有很大帮助!
慕然回首,灯火阑珊
都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。
所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。
强调一下,树层去重的话,需要对数组排序!
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int start_index) {
if (target == 0) {
result.push_back(path);
return;
}
for (int i = start_index; i < candidates.size() && target - candidates[i] >= 0; i++) {
if (i > start_index && candidates[i] == candidates[i-1]) { //去重操作
continue;
}
target -= candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, i+1);
target += candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end()); //去重需要排序
backtracking(candidates, target, 0);
return result;
}
};
LeetCode131. 分割回文串
题目链接:131. 分割回文串
独上高楼,望尽天涯
很有难度的一道题,需要分别处理切割和判断是否是回文串两个问题。
慕然回首,灯火阑珊
切割问题类似组合问题。
class Solution {
private:
vector<vector<string>> result;
vector<string> path;
bool isPalindrome(const string& s, int begin, int end) {
for (int i = begin, j = end; i < j; i++, j--) {
if (s[i] != s[j]) {
return false;
}
}
return true;
}
void backtracking(string s, int start_index) {
// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
if (start_index >= s.size()) {
result.push_back(path);
return;
}
// for循环横向遍历,寻找所有以start_index为首的回文子串
for (int i = start_index; i < s.size(); i++) {
if (isPalindrome(s, start_index, i)) {
string str = s.substr(start_index, i - start_index + 1);
path.push_back(str);
backtracking(s, i + 1);
path.pop_back();
}
}
}
public:
vector<vector<string>> partition(string s) {
backtracking(s, 0);
return result;
}
};
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |