【代码随想录算法训练营——Day23】回溯算法——39.组合总和、40.组合总和II、131.分割回文串
LeetCode题目链接
https://leetcode.cn/problems/combination-sum/description/
https://leetcode.cn/problems/combination-sum-ii/
https://leetcode.cn/problems/palindrome-partitioning/
题解
39.组合总和
写出了根据昨天的题目总结的代码,发现2,2,3和2,3,2这样的重复组合不知道怎么去重。看了一下题解,发现选一个数后,下次接着从这个数往后取,前面的数不取,这就相当于又多了一个start。仔细思索一下,要重复取数字,又不能有重复结果,因此每次从当前数重复取,后面的数字绝不会和前面的数重合,所以避免了重复结果。
40.组合总和II
仿照上一题的代码写出来有重复结果,比如1,7和7,1以及1,2,5和2,1,5。因为原数组有重复数字,而且每个数字只能用一次。
看了上面这段话,写出了下面这行代码,但把结果中有重复元素的结果也给求熬了,比如1,1,6。
if (i > 0 && candidates[i] == candidates[i - 1]) continue;
看到题解后面发现start来去重也是可以的,因为start从上一层传到当前树枝时(参考题解说法),该数还没有被用过,如果条件是i>0的话,后面没用过的相同数值的数就会被跳过,而i>start时,就可以保证当前的数即使等于上一个数也可以用一次。当从前一个数经过树枝到下一个数时,下一个数已被用过,再到上一层,如果还有相同的数待使用,则不用。相当于后面的数已经提前用过一次,当再有相同的数时,就不用。或者还可以有一个记忆方法,i>0时可以排除数组内的重复数,使得结果中每个数只出现一次;i>start时可以使用数组中的重复的数,使得结果可以出现重复数,但没有重复答案。
131.分割回文串
写了一些代码,有很多不确定的地方,交给chatGPT来处理:
首先要改的一个逻辑是,判断该子串是回文串时才放入path数组里。其次,取子串时,按当前的起始位置一直往后取。
代码
//39.组合总和
#include <iostream>
#include <vector>
using namespace std;class Solution {
public:vector<vector<int>> result;vector<vector<int>> combinationSum(vector<int>& candidates, int target) {vector<int> nums;backtracking(nums, candidates, target, 0);return result;}void backtracking(vector<int> nums, vector<int> candidates, int target, int start) {int sum = 0;for (int i = 0; i < nums.size(); i++) {sum += nums[i];}if (sum == target) {result.push_back(nums);return;}if (sum > target) return;for (int i = start;i < candidates.size();i++) {nums.push_back(candidates[i]);backtracking(nums, candidates, target, i);nums.pop_back();}}
};int main() {Solution s;vector<int> candidates1 = { 2,3,6,7 }, candidates2 = { 2,3,5 }, candidates3 = { 2 };int target1 =7, target2 =8, target3 = 1;vector<vector<int>> result = s.combinationSum(candidates3, target3);for (int i = 0;i < result.size();i++) {for (int j = 0;j < result[i].size();j++) {printf("%d ", result[i][j]);}printf("\n");}return 0;
}
//40.组合总和II
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;class Solution {
public:vector<vector<int>> result;vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<int> nums;sort(candidates.begin(), candidates.end());backtracking(nums, candidates, target, 0);return result;}void backtracking(vector<int> nums, vector<int> candidates, int target, int start) {int sum = 0;for (int i = 0; i < nums.size(); i++) {sum += nums[i];}if (sum == target) {result.push_back(nums);return;}if (sum > target) return;for (int i = start;i < candidates.size();i++) {if (i > start && candidates[i] == candidates[i - 1]) continue;nums.push_back(candidates[i]);backtracking(nums, candidates, target, i + 1);nums.pop_back();}}
};int main() {vector<int> candidates1 = { 10,1,2,7,6,1,5 }, candidates2 = { 2,5,2,1,2 };int target1 = 8, target2 = 5;Solution s;vector<vector<int>> result = s.combinationSum2(candidates2, target2);for (int i = 0;i < result.size();i++) {for (int j = 0;j < result[i].size();j++) {printf("%d ", result[i][j]);}printf("\n");}return 0;
}
//131.分割回文串
#include <iostream>
#include <vector>
using namespace std;class Solution {
public:vector<vector<string>> result;vector<vector<string>> partition(string s) {vector<string> path;backtracking(path, s, 0);return result;}void backtracking(vector<string> path, string s, int start) {if (start == s.size()) {result.push_back(path);return;}for (int i = start;i < s.size();i++) {string substr = s.substr(start, i - start + 1); //*************bool flag = true;for (int j = 0, k = substr.size() - 1;j <= k;j++, k--) {if (substr[j] != substr[k]) flag = false;}if (flag) {path.push_back(substr);backtracking(path, s, i + 1);path.pop_back();}}}
};int main() {string str1 = "aab", str2 = "a";Solution s;vector<vector<string>> result = s.partition(str1);for (int i = 0;i < result.size();i++) {for (int j = 0;j < result[i].size();j++) {cout << result[i][j] << " ";}cout << endl;}return 0;
}