day 27 第七章 回溯算法part03

总结

回溯不好在脑海里硬想,多动手画一次树形结构,这样分析回溯逻辑就更方便了

● 39. 组合总和
● 40.组合总和II
● 131.分割回文串

● 39. 组合总和

/*
 * 39. 组合总和
中等
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,
 找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
 */
class Solution_39 {
 public:
  /*
   * 定义全局遍历 path, res

输入参数为指定数组,目标和target,path当前和,单层起始下标
终止条件:和大于等于target
单层回溯逻辑:
    判断终止条件
    循环取当层数组的所有元素,从单层起始下开始
    获取到的元素加入path及其和
    递归,注意,因为可以重复选取,所以单层起始下标不加一
    回溯,去掉该层循环元素

    剪枝优化
    当sum大于target时应该停止该层循环
   */
  vector<vector<int>> res;
  vector<int> path;
  void back(vector<int>& candidates, int target, int sum, int start_index){
      //判断终止条件
      if(sum == target){
          res.push_back(path);
          return;
      } else if (sum > target){
          return;
      }
      //循环取当层数组的所有元素,从单层起始下开始
      //当sum大于target时应该停止该层循环
      for(int i = start_index; i < candidates.size() && sum + candidates[i] <= target; i++){
          //获取到的元素加入path及其和
          path.push_back(candidates[i]);
          sum += candidates[i];
          //递归,注意,因为可以重复选取,所以单层起始下标不加一
          back(candidates, target, sum, i);
          //回溯,去掉该层循环元素
          path.pop_back();
          sum -= candidates[i];
      }

  }
  vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
      back(candidates, target, 0, 0);
      return res;
  }
};

● 40.组合总和II

/*
 * 40. 组合总和 II
中等
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
 提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
 */

class Solution_40 {
 public:
  /*
 * 定义全局遍历 path, res

输入参数为指定数组,目标和target,path当前和,单层起始下标
终止条件:和大于等于target
单层回溯逻辑:
  判断终止条件
  循环取当层数组的所有元素,从单层起始下开始
  获取到的元素加入path及其和
  递归,每个数字在每个组合中只能使用 一次
  回溯,去掉该层循环元素

  剪枝优化
  当sum大于target时应该停止该层循环
 */
  vector<vector<int>> res;
  vector<int> path;

  void back(vector<int> &candidates, int target, int sum, int start_index, vector<int> &used) {
      //判断终止条件
      if (sum == target) {
          res.push_back(path);
          return;
      } else if (sum > target) {
          return;
      }
      //循环取当层数组的所有元素,从单层起始下开始
      //当sum大于target时应该停止该层循环
      for (int i = start_index; i < candidates.size() && sum + candidates[i] <= target; i++) {
          if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == 0) {
              continue;
          }
          //获取到的元素加入path及其和
          path.push_back(candidates[i]);
          sum += candidates[i];
          used[i] = 1;
          //递归,每个数字在每个组合中只能使用 一次
          back(candidates, target, sum, i + 1, used);
          //回溯,去掉该层循环元素
          path.pop_back();
          sum -= candidates[i];
          used[i] = 0;
      }

  }
  vector<vector<int>> combinationSum2(vector<int> &candidates, int target) {
      vector<int> used(candidates.size(), 0);
      // 首先把给candidates排序,让其相同的元素都挨在一起。
      sort(candidates.begin(), candidates.end());
      back(candidates, target, 0, 0, used);
      return res;
  }
};

● 131.分割回文串

/*
 * 131. 分割回文串
中等
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。
 */

class Solution_131 {
 public:
  /*
   * 输入参数为指定字符串,起始下标
终止条件:起始下标超过指定字符串大小,大于等于,因为起始下标从0开始
单层回溯逻辑:
    判断终止条件
    第一层循环用于不停增加子字符串的长度,遍历所有不同长度的子字符串
     判断该字符串是否为回文,双指针
     获取子字符串s[start_index, i],
     递归其余子字符串
     回溯
   */
  vector<vector<string>> res;
  vector<string> path;
  bool is_str(string &s, int start_index, int end){
      int i = start_index;
      int j = end;
      while (i < j){
          if(s[i] != s[j])
              return false;
          i += 1;
          j -= 1;
      }
      return true;
  }
  void back(string &s, int start_index){
      //判断终止条件
      if(start_index >= s.size()){
          res.push_back(path);
      }
      //第一层循环用于不停增加子字符串的长度,遍历所有不同长度的子字符串
      for(int i = start_index; i < s.size(); i++){
          //判断该字符串是否为回文,双指针
          if(is_str(s, start_index, i)){
              //获取子字符串s[start_index, i],
              path.push_back(s.substr(start_index, i - start_index + 1));
              //递归其余子字符串
              back(s, i + 1);
              //回溯
              path.pop_back();
          } else
              continue;
      }
  }
  vector<vector<string>> partition(string s) {
      back(s, 0);
      return res;
  }
};
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值