递归&回溯

本文深入探讨了回溯算法和递归的概念,通过全排列问题和二叉树路径求和展示了这两种算法的实现。回溯算法涉及路径、选择列表和结束条件,递归则关注终止条件、本级任务和返回信息。举例中,回溯用于找出数组的全排列,而递归解决了二叉树路径和问题。同时,文章强调理解递归的递推公式对于编写递归代码至关重要。
摘要由CSDN通过智能技术生成

一、回溯
  解决一个回溯问题,实际上就是一个决策树的遍历过程,只需要考虑三个问题。
1、路径:也就是已经做出的选择。
2、选择列表:就是当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。

回溯算法框架:

result = []
def backtrack(路径, 选择列表):
	 if 满足结束条件:
	 	result.add(路径)
	 	return
	 for 选择 in 选择列表:
	 	做选择
	 	backtrack(路径,选择列表)
	 	撤销选择

例题:全排列问题

在这里插入图片描述
  如上:2是路径,表示已经做出的选择,1,3是选择列表,即可以做出的选择。
代码(java):

List<List<Integer>> res = new LinkedList<>();
//输入一组不重复的数组,返回他们的全排列
List<List<Integer>> permute(int[] nums) {
    // 记录「路径」
    LinkedList<Integer> track = new LinkedList<>();
    backtrack(nums, track);
    return res;
}
//路径记录在track中
//选择列表:nums中不存在于track的那些元素
//结束条件:nums中的元素全部在track中出现
void backtrack(int[] nums, LinkedList<Integer> track) {
    // 触发结束条件
    if (track.size() == nums.length) {
        res.add(new LinkedList(track));
        return;
    }
    for (int i = 0; i < nums.length; i++) {
        // 排除不合法的选择
        if (track.contains(nums[i]))
            continue;
        // 做选择
        track.add(nums[i]);
        // 进入下一层决策树
        backtrack(nums, track);
        // 取消选择
        track.removeLast();
    }

例题
在这里插入图片描述

    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> pathSum(TreeNode* root, int target) {
        recur(root,target);
        return res;
    }
    void recur(TreeNode* root,int target)
    {
    if(root==nullptr) return;
    path.push_back(root->val);
    target-=root->val;
    if(target==0&&root->left==nullptr&&root->right==nullptr)
    res.push_back(path);
    recur(root->left,target);
    recur(root->right,target);
    path.pop_back();    重要!!!!!!向上回溯前,需要将当前节点从路径 path 中删除,即执行 path.pop()}

二、递归
  每当递归函数调用自身时,他都会将给定的问题拆解为子问题,递归调用继续进行,直到子问题无需进一步递归就可以解决的地步。

例子:反转字符串
递归应该关注的三个点:
1、终止条件
2、本级递归的任务
3、返回上一级的信息
针对本题来讲
本题的终止条件是 数组下标移动到中间位置以后便不再交换

本级递归层要完成的是交换两个字符

返回值:传递给下一次递归的是 字符串和下标

class Solution {
public:
    void reverse(vector<char>& s,int i){
        //1.终止条件
        int len=s.size();//获取字符的长度
        if(i>=(len/2)){
            return;
        }
        //2.交换首尾
        char c=s[i];
        s[i]=s[len-i-1];
        s[len-i-1]=c;
        //3.返回给上一层递归的参数
        reverse(s,i+1); 
    }
    void reverseString(vector<char>& s) {
        reverse(s,0);
    }
};

  其实写递归不能想着去把递归平铺展开,一层层的下调再返回会搞乱,其实只要找到递推公式就可以轻松的写出递归代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值