首页 > 其他分享 >(26/60)组合总和、组合总和Ⅱ、分割回文串

(26/60)组合总和、组合总和Ⅱ、分割回文串

时间:2024-02-25 11:55:59浏览次数:31  
标签:26 target 组合 int 复杂度 vector candidates sum 总和

组合总和

leetcode:39. 组合总和

回溯法

思路

在组合的基础上,只不过同一个数字可以重复选取,递归时传入i即可(组合是传入i+1)。

复杂度分析

时间复杂度:

  • 在最坏情况下,回溯算法会遍历所有可能的组合,因此时间复杂度取决于解的个数。假设候选数组的长度为n,目标值为target,最坏情况下解的个数为O(2^n)。
  • 在每个解中,我们需要遍历当前候选数组的剩余部分,因此在每个递归层级中,时间复杂度为O(n-i),其中i为当前层级的起始位置。

综上所述,整体的时间复杂度为O(2^n * n)。

空间复杂度:

  • 回溯算法使用了额外的空间来存储当前路径和结果集,因此空间复杂度取决于解的个数和每个解的平均长度。
  • 结果集的空间复杂度为O(2^n * avg_len),其中avg_len是每个解的平均长度。
  • 当前路径的空间复杂度为O(n)。
  • 综上所述,整体的空间复杂度为O(2^n * avg_len + n)。

(avg_len无法确定)

注意点

  1. 对循环的剪枝:如果 sum + candidates[i] > target 就终止遍历

代码实现

剪枝:如果 sum + candidates[i] > target 就终止遍历

class Solution {
private: 
    vector<int> path;
    vector<vector<int>> result;
    int sum = 0;
public:
    void backtracking(vector<int>& candidates,int target,int begin){
        if(sum == target) result.push_back(path);
        else if(sum > target) return;
		
        // 剪枝:如果 sum + candidates[i] > target 就终止遍历
        for(int i = begin;i < candidates.size() && sum + candidates[i] <= target;i++){
            path.push_back(candidates[i]);
            sum += candidates[i];
            backtracking(candidates,target,i); // 注意,传递的是i不是begin
            path.pop_back();
            sum -= candidates[i];
        }

    }

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

组合总和Ⅱ

思路

重点是去重。

首先把原数组排序,用used数组标记是否使用过。

若当前元素与上一元素相等,如果used[i-1]为true,说明是树枝部分重复,可以继续;如果used[i-1]为false,说明在树层部分重复,需要跳过,去重。

40.组合总和II1

复杂度分析

时间复杂度:

  • 在最坏情况下,回溯算法会遍历所有可能的组合。假设候选数组的长度为n,目标值为target,那么最坏情况下,解的个数为O(2^n)。
  • 在每个解中,我们需要遍历当前候选数组的剩余部分,因此在每个递归层级中,时间复杂度为O(n-i),其中i为当前层级的起始位置。
  • 综上所述,整体的时间复杂度为O(2^n * n)。

空间复杂度:

  • 回溯算法使用了额外的空间来存储当前路径和结果集,因此空间复杂度取决于解的个数和每个解的平均长度。
  • 结果集的空间复杂度为O(2^n * avg_len),其中avg_len是每个解的平均长度。
  • 当前路径的空间复杂度为O(n)。
  • 综上所述,整体的空间复杂度为O(2^n * avg_len + n)。

注意点

  1. 去重的要素:数组有序、相邻两个元素是否相等、used数组标记是否使用过。

    不要忘记先排序!

代码实现

class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;

public:
    void backtracking(vector<int>& candidates,int target,vector<bool> used,int begin,int sum){
        if(sum == target){
            result.push_back(path);
            return;
        }else if(sum > target) return;

        for(int i = begin;i < candidates.size() && sum < target;i++){
            // 去重
            // 第一个==表示相邻两个元素值相等;
            // 第二个==表示上一个元素已经使用过
            // 只有上一个元素使用过,且当前元素值等于上一元素时,跳过,树层去重
            if(i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false) continue;
            path.push_back(candidates[i]);
            sum += candidates[i];
            used[i] = true;
            backtracking(candidates,target,used,i+1,sum);
            path.pop_back();
            sum -= candidates[i];
            used[i] = false;
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> used(candidates.size(),false);
        sort(candidates.begin(),candidates.end());
        backtracking(candidates,target,used,0,0);
        return result;
    }
};

不使用used数组:

    class Solution {
    private:
        vector<int> path;
        vector<vector<int>> result;

    public:
        void backtracking(vector<int>& candidates,int target,int begin,int sum){
            if(sum == target){
                result.push_back(path);
                return;
            }else if(sum > target) return;

            for(int i = begin;i < candidates.size() && sum < target;i++){
                // 跳过同一树层使用过的元素
                if(i > begin && candidates[i - 1] == candidates[i]) continue;
                path.push_back(candidates[i]);
                sum += candidates[i];
                backtracking(candidates,target,i+1,sum);
                path.pop_back();
                sum -= candidates[i];
            }
        }

        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<bool> used(candidates.size(),false);
            sort(candidates.begin(),candidates.end());
            backtracking(candidates,target,0,0);
            return result;
        }
    };

分割回文串

leetcode:131. 分割回文串

回溯法

思路

基础可以看作是不重复使用的组合问题。每次在子串中分割,分隔符就是begin这个下标。子串就是begin~i这个范围。

复杂度分析

时间复杂度:O(n * 2^n)。

空间复杂度:O(n^2)。

注意点

  1. 回文判断别写错,if(s[i] != s[j]) return false;

代码实现

class Solution {
private:
    vector<vector<string>> result;
    vector<string> path;
public:
    void backtracking(string& s,int begin){
        if(begin >= s.size()){
            result.push_back(path);
            return;
        }
        
        for(int i = begin;i < s.size();i++){
            if(isPalindrome(s,begin,i)){
                path.push_back(s.substr(begin,i - begin + 1));
                backtracking(s,i+1);
                path.pop_back();
            }
        }
    }

    // 左闭右闭
    bool isPalindrome(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;
    }

    vector<vector<string>> partition(string s) {
        backtracking(s,0);
        return result;
    }
};

标签:26,target,组合,int,复杂度,vector,candidates,sum,总和
From: https://www.cnblogs.com/tazdingo/p/18032214

相关文章

  • 对边不交图结构的解析组合分析
    图论题定义\(n\)个结点的平面图是满足如下条件的图:\(n\)个结点按标号在平面上顺序排列为一个正\(n\)边形。边是连接两个结点的直线段,任意两条边不在除端点外的位置交叉。定义一个平面图的极大连通分量为一个极大的结点集合,满足任意两个集合内节点联通。给定询问类型......
  • (25/60)组合总和Ⅲ、电话号码的字母组合
    组合总和Ⅲleetcode:216.组合总和III回溯法思路组合的基础上,在找组合的过程中,把和为N的记录下来。复杂度分析时间复杂度:O(C(K,9))。空间复杂度:空间复杂度主要来自递归调用时维护的栈空间和存储结果的二维数组,分别为O(k)和O(C(K,9)*K)。注意点略代码实现classSolut......
  • 代码随想录算法训练营第二十六天| 39. 组合总和 40.组合总和II 131.分割回文串
    组合总和题目链接:39.组合总和-力扣(LeetCode)思路:依然一是套用回溯模板,但是我们这里用回溯的是i而不是i+1,因为元素可以重复使用,注意for循环里if(sum(path)<=target)的等号不能少。classSolution{public:vector<int>path;vector<vector<int>>result;intsu......
  • java面向对象之封装-抽象-继承-组合-多态五种概念一网打尽
    说明曾经在学习java面向对象时,你是否会为面向对象的封装-继承-抽象-多态-组合等各种概念搞得稀里糊涂,乃至反复阅读,背诵其相关概念,结果一段时间过后又还给了时间。。。这种经历简直令人发指,让人无法忍受,难道就没有哪个地方能把它一次说清楚,老百姓看了以后纷纷醍醐灌顶,不再重蹈覆......
  • day 26
    第26-27天:开始小型项目在这两天里,我启动了一个小型项目,项目的主要目标是涵盖用户认证、数据查询和报表展示功能。具体步骤如下:用户认证:实现基本的用户注册和登录功能,使用Servlet处理用户提交的注册和登录请求。使用数据库存储用户信息,包括用户名、密码等。引入会话管理机......
  • 2024省选模拟26联测23
    T1首先,存在一个显然的事情:若集合\(S\)满足要求,那么\(S\)的任何子集也满足要求。还有一个比较显然的事实:对于一个合法的集合,其每个元素的位置一定在范围的交内。难道要用奇怪的容斥???但是好像根本容斥不了。。。。哈哈。能不能考虑减去不合法的状态?也许可以连边找完全图???好......
  • P8026 [ONTAK2015] Bajtocja
    P8026[ONTAK2015]Bajtocja题目描述给定d张无向图,每张图都有n个点。一开始,在任何一张图中都没有任何边。接下来有m次操作,每次操作会给出a,b,k,意为在第k张图中的点a和点b之间添加一条无向边。你需要在每次操作之后输出有序数对(a,b)的个数,使得1≤a,b≤n,且a点......
  • 代码随想录算法训练营第二十五天| 216.组合总和III 17.电话号码的字母组合
    组合总和III题目链接:216.组合总和III-力扣(LeetCode)思路:仿照昨天的递归模板写的,同样是for循环横向遍历,递归纵向遍历。注意当k>n时要直接跳出,否则会判断栈溢出。额外发现一个问题就是在累加sum时,用for(autoi:path)sum+=path[i];会出现奇怪数字,原因是auto遍历用法错误,正确写......
  • 代码随想录算法训练营第二十五天 | 17.电话号码的字母组合 , 216.组合总和III
    216.组合总和III 已解答中等 相关标签相关企业 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:只使用数字1到9每个数字 最多使用一次返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回......
  • 又一例:ORA-600 kclchkblk_4和2662故障---惜分飞
    又一例:ORA-600kclchkblk_4和2662故障发表于 2024年2月21日 由 惜分飞联系:手机/微信(+8617813235971)QQ(107644445)标题:又一例:ORA-600kclchkblk_4和2662故障作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.]有客户恢......