算法训练营day27

总结

多数情况递归回溯的返回值是void;

递归存路径的时候,回溯pop了,就不用在存答案之后clear了,因为每层都会pop;

组合dfs的时候:

dfs进去就是利用for循环往下延申树枝之间的纵向交流,回溯回来就是利用for循环一层一层之间的横向交流;

涉及到去重,一般就是先排个序;

剪枝就是在for循环的时候剪了直接,不符合的情况就不要dfs了,一般配合排序;

use作用有两个:

树层去重(如1215,取了12就不能取21了,这种情况先排序为1125,前一个1已经把组合都给组了,后一个1就不能组了,这是重复);树枝去重(如1125,不能取112,树枝元素不能相同);

之所以要加个used,是因为单纯的candidates[i]==candidates[i-1]会把树层的 树枝的都给去重,题目只要求了树层or树枝去重就不能这样干;

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)//说明同一树层使用过s
if(i>0&&candidates[i] == candidates[i - 1] && used[i - 1] == true)//说明同一树枝使用过

递归参数中有不变量(主函数要传进来的),也有变量,需要注意;

递归就是当前层做什么,下一层做什么,代码是相同的;

39.组合总和

写一个dfs函数,返回值为0,参数为位置u,与目标值的差值cnt,原数组;

每个数没有取值数量限制,所以循环中,把自己加上,每层都取自己就是多数量的情况;

class Solution {
public:
    vector<int> V;
    vector<vector<int>> ans;
    int n;
    
    void dfs(int u,int cnt,vector<int> candidates){
        if(cnt==0){
            ans.push_back(V);
            return;
        }
        if(cnt<0||u==n) return;
        for(int i=u;i<n;i++){
            V.push_back(candidates[i]);
            dfs(i,cnt-candidates[i],candidates);
            V.pop_back();
        }
        return;
    }
    
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        ans.clear();
        V.clear();
        n=candidates.size();
        dfs(0,target,candidates);
        return ans;
    }
};

40.组合总和II

10,1,2,7,6,1,5中17与71重复;

树层去重,先排个序11256710,举个例子,保证第一个1组合过的17,后面的1不组合了就;

用used标记数组来配合去重;注意向下延申的时候,可以取11,仅仅是树层维度1去过了,后面的1不取;

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> V;
    int n;
    void dfs(int u,int cnt,vector<int> candidates,vector<bool> used){
        if(cnt==0){
            ans.push_back(V);
            return;
        }
        if(cnt<0||u==n) return;
        
        for(int i=u;i<n&&candidates[i]<=cnt;i++){
            if(i>=1&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue; 

            used[i]=true;
            V.push_back(candidates[i]);
            dfs(i+1,cnt-candidates[i],candidates,used);
            used[i]=false;
            V.pop_back();
        }
        return;
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
          ans.clear();
          V.clear();
          vector<bool> used(candidates.size(),false);
          sort(candidates.begin(),candidates.end());
            n=candidates.size();
          dfs(0,target,candidates,used);
          return ans;  
    }
};

131.分割回文串

分割回文串,其实跟组合数很像,首先画出递归搜索树;

for横向遍历,递归纵向遍历,函数参数为字符串s,起始位置u;

到头了,递归终止,把V放到ans;

判断是否回文,如果回文,放到V里,dfs下一段,记得回溯要恢复现场;

class Solution {
public:
    vector<string> V;
    vector<vector<string>> ans;
    
    bool check(string s,int l,int r){
        for(int i=l,j=r;i<j;i++,j--){
            if(s[i]!=s[j]) return false;
        }
        return true;
    }

    void dfs(string s,int u){
        if(u>=s.size()){
            ans.push_back(V);
            return;
        }
        for(int i=u;i<s.size();i++){
            if(check(s,u,i)){
                string t=s.substr(u,i-u+1);
                V.push_back(t);
                dfs(s,i+1);
                V.pop_back();
            }
        }
        return;
    }

    vector<vector<string>> partition(string s) {
        V.clear();
        ans.clear();
        dfs(s,0);
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邓俊辉教授是计算机科学与技术领域著名的教育家和研究者。他在清华大学担任教授,并负责计算机算法与理论方向的研究和教学工作。邓俊辉教授是中国计算机学会副理事长、国际著名科技出版社Springer中国系列丛书主编、IEICE China Communications主编、Journal of Internet Technology编委、《数据结构与算法教程》作者等。 在邓俊辉教授的指导下,他办了多次Dijkstra算法训练营,旨在培养学生对于算法学习的兴趣与能力。Dijkstra算法是一种用于图论中求解最短路径问题的经典算法,具有广泛的应用领域,如路由算法、网络规划和GPS导航系统等。在训练营中,邓俊辉教授通过讲解算法的原理和思想,引导学生进行编程实践和案例分析,帮助他们深入理解Dijkstra算法的应用场景与实际解决问题的能力。 邓俊辉教授所组织的Dijkstra算法训练营受到了广大学生的欢迎和积极参与。通过训练营的学习,学生不仅可以掌握Dijkstra算法的具体实现过程,还能了解算法设计的思路和应用的局限性。在训练营中,学生还可以与同学们进行交流和合作,共同解决实际问题,促进彼此的学术成长和人际交往能力的培养。 总之,邓俊辉的Dijkstra算法训练营为学生提供了一个系统、全面学习算法知识的平台,帮助他们培养解决实际问题的能力和思维方式。通过这样的培训,学生不仅能在学术领域取得更好的成绩,还可以为将来的职业发展打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值