Day 22 77. 组合 216.组合总和III 17.电话号码的字母组合

任务日期:6.27,今天开始回溯算法的章节,由于最近期末周所以递归章节学得不好,希望到了假期可以好好补补。现在尽可能地认真学习回溯算法,避免欠债。

回溯算法

1.用途:

代码模版:

void backtracking(参数) {
    if (终止条件) {//确定递归终止条件
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {//确定单层递归逻辑
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

题目一链接:77. 组合 - 力扣(LeetCode)

思路:1.确定函数返回值和参数:在这里要定义两个全局变量,一个用来存放符合条件单一结果,一个用来存放符合条件结果的集合,所以我定义全局变量了;startIndex 就是防止出现重复的组合。
2.确定终止条件:path这个数组的大小如果达到k,说明我们找到了一个子集大小为k的组合了,在图中path存的就是根节点到叶子节点的路径。
3.确定单层递归逻辑:for循环每次从startIndex开始遍历,然后用path保存取到的节点i。可以看出backtracking(递归函数)通过不断调用自己一直往深处遍历,总会遇到叶子节点,遇到了叶子节点就要返回。backtracking的下面部分就是回溯的操作了,撤销本次处理的结果,方便返回上一层可以继续填入值。

代码:

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(int n,int k,int startIndex) {
        //递归结束条件
        if(path.size() == k) {
            result.push_back(path);
            return;
        }
        //单层递归逻辑:
        for(int i = startIndex;i <= n - (k - path.size()) + 1;i ++) { //减枝操作:i的最大的开始值。
            path.push_back(i);//处理节点
            backtracking(n,k,i + 1);//递归,startIndex应该从i + 1开始
            path.pop_back();//回溯:递归到一个结果后会自动返回上一层,这时候要弹出一个值。
        }
    }

    vector<vector<int>> combine(int n, int k) {
        backtracking(n,k,1);
        return result;
    }
};

难点:

总结:难点主要在单层递归逻辑上,先处理节点后进行递归,递归还要改变开始的值。

减枝操作:i <= n - (k - path.size()) + 1




题目二链接:216. 组合总和 III - 力扣(LeetCode)

思路:1.确定递归函数参数:和77. 组合 (opens new window)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。这里我依然定义path 和 result为全局变量。
2.确定递归终止条件:所以如果path.size() 和 k相等了,就终止;当sum的值比n大时,也就终止了。
3.确定单层递归逻辑:处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和。然后进行递归和回溯

代码:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(int k,int n,int sum,int startIndex) {
        //确定递归终止条件
        if(sum > n) return;//剪枝操作:当sum大于n时,当前递归就可以结束了
        if(path.size() == k) {
            if(sum == n) result.push_back(path);//sum等于n的时候才计入result里
            return;
            }
        //单层递归逻辑
        for(int i = startIndex;i <= 9 - (k - path.size()) + 1;i ++) {//剪枝操作
            path.push_back(i);
            sum += i;//递归要加值
            backtracking(k,n,sum,i + 1);// 注意i+1调整startIndex
            sum -= i;//回溯要减值
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(k,n,0,1);//在这把sum的值传入;starIndex防止答案重复
        return result;
    }
};

难点:




题目三链接:17. 电话号码的字母组合 - 力扣(LeetCode)

思路:

代码:

class Solution {
public:
   const string lettermap[10] = {
        "","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz",
    };
    string s;
    vector<string> result;
    void backtracking(const string& digits,int index) {//index 表示当前遍历到第几个数字,也是递归的深度
        if(index == digits.size()) {    
            result.push_back(s);
            return;
        }

        int digit = digits[index] - '0';//把数字字符串里的数转化为int值
        string letters = lettermap[digit];//然后将字符串数组里的字符串传给当前字符串
        for(int i = 0;i < letters.size();i ++) {//递归宽度的遍历
            s.push_back(letters[i]);
            backtracking(digits,index + 1);
            s.pop_back();
        }
    }

    vector<string> letterCombinations(string digits) {
        if(digits.size() == 0) return result;//注意字符串的空“”和真空不一样,所以这里要加个特判
        backtracking(digits,0);//注意index初始值是0,字符数组的下标
        return result;
    }
};

难点:

解释细节1:

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值