代码随想录算法训练营第二十七天(二十六天休息) | 39. 组合总和、40、组合总和 II、131. 分割回文串
39. 组合总和
题目
解法
- 初始解法:出现重复组合,每一次递归从头开始了
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum) {
if(sum == target) {
result.push_back(path);
return ;
}
if (sum > target) return;
for (int i = 0; i < candidates.size(); i++) {
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum);
path.pop_back();
sum -= candidates[i];
}
return ;
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
int sum = 0;
backtracking(candidates, target, sum);
return result;
}
};
2.看完题解之后:加上startIdx之后,使用重复元素只使用一次;
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIdx) {
if(sum == target) {
result.push_back(path);
return ;
}
if (sum > target) return;
// sum + candidates[i] > target 会终止遍历 所以candidates 需要排序
for (int i = startIdx; i < candidates.size() && sum + candidates[i] <= target; i++) { // 剪枝优化
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i);
path.pop_back();
sum -= candidates[i];
}
return ;
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, 0, 0);
return result;
}
};
40、组合总和 II
题目
解法
- 初始想法+题解: 对于重复元素自取一次的逻辑(只取同一树枝上的)
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIdx) {
if(sum == target) {
result.push_back(path);
return ;
}
if (sum > target) return;
// sum + candidates[i] > target 会终止遍历 所以candidates 需要排序
for (int i = startIdx; i < candidates.size() && sum + candidates[i] <= target; i++) { // 剪枝优化
if(i > startIdx && candidates[i] == candidates[i-1]) continue ; // 去重 同一树层去重
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i + 1);
path.pop_back();
sum -= candidates[i];
}
return ;
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
result.clear();
path.clear();
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, 0, 0);
return result;
}
};
2.使用数组储存是否已经使用过同一树层的元素
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIdx, vector<bool> used) {
if(sum == target) {
result.push_back(path);
return ;
}
if (sum > target) return;
// sum + candidates[i] > target 会终止遍历 所以candidates 需要排序
for (int i = startIdx; i < candidates.size() && sum + candidates[i] <= target; i++) { // 剪枝优化
// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
// 要对同一树层使用过的元素进行跳过
if(i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false) continue ; // 去重 同一树层去重
sum += candidates[i];
path.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, target, sum, i + 1, used);
used[i] = false;
path.pop_back();
sum -= candidates[i];
}
return ;
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<bool> used(candidates.size(), false);
result.clear();
path.clear();
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, 0, 0, used);
return result;
}
};
131. 分割回文串
题目
解法
- 看完题解之后
class Solution {
private:
vector<vector<string>> result;
vector<string> path;
void backtracking(string s, int startIdx) {
if (startIdx >= s.size()) {
result.push_back(path);
return ;
}
for (int i = startIdx; i < s.size(); i++) {
if(isHuiWen(s, startIdx, i)) {
string str = s.substr(startIdx, i - startIdx + 1);
path.push_back(str);
}else {
continue;
}
backtracking(s, i + 1);
path.pop_back();
}
return ;
}
bool isHuiWen(string s, int start, int end) {
for(int i = start, j = end; i < j; i++, j--) {
if(s[i] != s[j]) return false;
}
return true;
}
public:
vector<vector<string>> partition(string s) {
result.clear();
path.clear();
backtracking(s, 0);
return result;
}
};
substr()用法
在C++中,substr() 是一个常用于 std::string 类的成员函数,用于获取字符串的子串。这个函数的基本语法如下:
std::string substr(size_t pos = 0, size_t count = npos) const;
pos:这是子串开始的位置(基于0的索引)。如果 pos 大于字符串的长度,则 substr() 函数会抛出一个 std::out_of_range 异常。
count:这是要提取的字符数。如果 count 是 std::string::npos 或大于从 pos 到字符串末尾的字符数,则子串将包括从 pos 开始到字符串末尾的所有字符。
以下是一些使用 substr() 函数的示例:
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 从位置0开始,提取5个字符
std::string substr1 = str.substr(0, 5); // "Hello"
std::cout << substr1 << std::endl;
// 从位置7开始,提取到字符串结束
std::string substr2 = str.substr(7); // "World!"
std::cout << substr2 << std::endl;
// 从位置7开始,提取4个字符
std::string substr3 = str.substr(7, 4); // "Worl"
std::cout << substr3 << std::endl;
return 0;
}
注意,如果提供的 pos 超出了字符串的范围,substr() 函数会抛出一个 std::out_of_range 异常。因此,在使用 substr() 函数时,最好确保 pos 的值在有效范围内。
此外,还要注意的是,substr() 函数返回的是一个新的字符串,它包含原字符串中指定位置的子串。原字符串本身不会被修改。
感悟
关键细节要理解清楚,比如startIdx的使用