zoukankan      html  css  js  c++  java
  • 【LeetCode】Combination Sum

    给定一组候选正整数集合Set(没有重复元素)和一个目标正整数 target,找到 Set 中所有的数字组合(可以不限次数地选择同样的数字),使其和 = target。结果集中不能有重复

    e.g. 给定候选正数集 [2, 3, 6, 7] 和target = 7,返回结果集

    [
        [7],
        [2, 2, 3]
    ]

    我的想法是用递归实现,但结果集去重我想了两种低效的方法。

    第一种:

     1 vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
     2     vector<vector<int>> result;
     3     vector<int> item;
     4     addItem(result, candidates, item, target);
     5     sort(result.begin(), result.end());
     6     result.erase(unique(result.begin(), result.end()), result.end());
     7     return result;
     8 }
     9     
    10 void addItem(vector<vector<int>>& result, vector<int>& candidates, vector<int> item, int target) {
    11     if (target == 0) {
    12         sort(item.begin(), item.end());
    13         result.push_back(item);
    14         return;
    15     }
    16     for (int i = 0; i < candidates.size(); i++) {
    17         if (candidates[i] <= target) {
    18             item.push_back(candidates[i]);
    19             addItem(result, candidates, item, target - candidates[i]);
    20             item.pop_back();
    21         }
    22     }
    23     return;
    24 }

    unique 函数的作用是“删除” vector 中所有相邻的重复元素,只留一个。

    由于 unique 只是去除相邻的重复元素,因此应首先对 vector 进行排序,保证重复元素在相邻的位置。

    注意,unique 并不是把重复的元素删除,而是全部放倒 vector 后面(vector 长度没变,顺序改变)。

    其本身会返回一个迭代器,返回的是去重后的尾地址,也即指向第一个重复元素。

    例如对于 vector {1, 1, 2, 2, 3},执行 unique 函数后,vector 变成了 {1, 2, 3, 1, 2},并且函数的返回值为 3。

    因此对 vector 去重可使用这种方法:

    sort(v.begin(),v.end());
    v.erase(unique(v.begin(), v.end()), v.end());

    第二种:

     1 vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
     2     vector<vector<int>> result;
     3     vector<int> item;
     4     addItem(result, candidates, item, target);
     5     return result;
     6 }
     7     
     8 void addItem(vector<vector<int>>& result, vector<int>& candidates, vector<int> item, int target) {
     9     if (target == 0) {
    10         sort(item.begin(), item.end());
    11         if (find(result.begin(), result.end(), item) == result.end())
    12             result.push_back(item);
    13         return;
    14     }
    15     for (int i = 0; i < candidates.size(); i++) {
    16         if (candidates[i] <= target) {
    17             item.push_back(candidates[i]);
    18             addItem(result, candidates, item, target - candidates[i]);
    19             item.pop_back();
    20         }
    21     }
    22     return;
    23 }

    使用 find 函数,如果 find(v.begin(), v.end(), val) 返回的迭代器到容器尾 v.end(),则说明 v 内不存在 val。

    答案在递归函数中增加了 begin 参数,并开始就对 candidates 进行排序,这样添加进结果集的 item 就不会有重复的。

     1 vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
     2     vector<vector<int>> result;
     3     vector<int> item;
     4     sort(candidates.begin(), candidates.end());
     5     addItem(result, candidates, item, target, 0);
     6     return result;
     7 }
     8     
     9 void addItem(vector<vector<int>>& result, vector<int>& candidates, vector<int> item, int target, int begin) {
    10     if (target == 0) {
    11         result.push_back(item);
    12         return;
    13     }
    14     for (int i = begin; i < candidates.size() && candidates[i] <= target; i++) {
    15         item.push_back(candidates[i]);
    16         addItem(result, candidates, item, target - candidates[i], i);
    17         item.pop_back();
    18     }
    19     return;
    20 }

    改变条件candidates 存在重复元素,而数字组合不能不限次数取同样的数字,只能有多少取多少。结果集同样不能有重复。

    e.g. 给定候选集合为 [10, 1, 2, 7, 6, 1, 5] 和 target = 8,返回结果集

    [
        [1, 7],
        [1, 2, 5],
        [2, 6],
        [1, 1, 6]   (1 在 candidates 中有 2 个就可以用 2 次
    ]

     1 vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
     2     vector<vector<int>> result;
     3     vector<int> item;
     4     sort(candidates.begin(), candidates.end());
     5     addItem(result, candidates, item, target, 0);
     6     return result;
     7 }
     8     
     9 void addItem(vector<vector<int>>& result, vector<int>& candidates, vector<int> item, int target, int begin) {
    10     if (target == 0) {
    11         result.push_back(item);
    12         return;
    13     }
    14     for (int i = begin; i < candidates.size() && candidates[i] <= target; i++) {
    15         while (i > begin && candidates[i] == candidates[i - 1]) i++;
    16         item.push_back(candidates[i]);
    17         addItem(result, candidates, item, target - candidates[i], i + 1);
    18         item.pop_back();
    19     }
    20     return;
    21 }

    用 while (i > begin && candidates[i] == candidates[i - 1]) i++; 和 addItem(result, candidates, item, target - candidates[i], i + 1); 控制重复!

  • 相关阅读:
    linux驱动开发学习一:创建一个字符设备
    如何高效的对有序数组去重
    找到缺失的第一个正整数
    .NET不可变集合已经正式发布
    中国人唯一不认可的成功——就是家庭的和睦,人生的平淡【转】
    自己动手搭建 MongoDB 环境,并建立一个 .NET HelloWorld 程序测试
    ASP.NET MVC 中如何用自定义 Handler 来处理来自 AJAX 请求的 HttpRequestValidationException 错误
    自己动手搭建 Redis 环境,并建立一个 .NET HelloWorld 程序测试
    ServiceStack 介绍
    一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL
  • 原文地址:https://www.cnblogs.com/wayne793377164/p/7205776.html
Copyright © 2011-2022 走看看