【递归、搜索与回溯】DFS | 回溯 | 剪枝

news2024/11/26 20:36:23

一、经验总结

在这里插入图片描述

实际上递归、深度优先搜索(DFS)、回溯与剪枝研究的是同一类问题,我将其统称为递归深搜算法,其解题步骤大致如下:

  1. 画出递归决策树:如果遇到较为复杂的递归题目,可以通过画出决策树明晰递归流程,再抽象出递归的三个核心问题:函数头、函数体、递归出口。分析问题的角度不同,画出的决策树就可能不同,编写的递归函数也可能不同。

  2. 全局变量:在递归算法中常用到全局变量,全局变量的优势在于在递归和回溯的过程中保证每一层遍历访问的都是同一个变量。常用于收集结果、记录递归路径等。

  3. 回溯恢复现场:与全局变量的需求正好相反,在递归算法中某些变量需要在回溯到上一层递归后恢复现场。如果该变量为全局变量则需要在回溯到上一层后手动恢复;如果该变量为局部变量(局部参数),则每层递归的变量都是全新、独立的变量不会相互影响,在回溯过程中能够自动实现“恢复现场”。

  4. 剪枝优化:在回溯过程中,如果目前已经能够得出结论,则没有必要继续递归遍历其他分支,可以直接返回。排除对解没有贡献的分支,可以减少搜索空间。


二、相关编程题

2.1 计算布尔二叉树的值

题目链接

2331. 计算布尔二叉树的值 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    bool evaluateTree(TreeNode* root) {
        if(root->val==0)  return false;
        if(root->val==1) return true;
        bool bleft = evaluateTree(root->left);
        bool bright = evaluateTree(root->right);
        if(root->val==2) return bleft || bright;
        else return bleft && bright;
    }
};

2.2 求根节点到叶节点数字之和

题目链接

129. 求根节点到叶节点数字之和 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    int sumNumbers(TreeNode* root) {
        return DFS(root, 0);
    }

    int DFS(TreeNode* root, int prev)
    {
        prev = prev*10+root->val;
        if(root->left==nullptr && root->right==nullptr)
            return prev;
        int ret = 0;
        if(root->left!=nullptr)
            ret += DFS(root->left, prev);
        if(root->right!=nullptr)
            ret += DFS(root->right, prev);
        return ret;
    }
};

2.3 二叉树剪枝

题目链接

814. 二叉树剪枝 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    TreeNode* pruneTree(TreeNode* root) {
        if(root == nullptr) return nullptr;
        root->left = pruneTree(root->left);
        root->right = pruneTree(root->right);
        if(root->left == nullptr && root->right == nullptr && root->val==0)
        {
            delete root;
            return nullptr;
        }
        else
            return root;
    }
};

2.4 验证二叉搜索树

题目链接

98. 验证二叉搜索树 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    long prev = LONG_MIN; //防止进行比较的第一个节点就是INT_MIN
public:
    bool isValidBST(TreeNode* root) {
        if(root == nullptr) return true;
        if(!isValidBST(root->left)) //剪枝
            return false;
        if(root->val <= prev) //剪枝
            return false;
        prev = root->val;
        if(!isValidBST(root->right))
            return false;
        return true;
    }
};

2.5 二叉搜索树中第K小的元素

题目链接

230. 二叉搜索树中第K小的元素 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    int count, ret;
public:
    int kthSmallest(TreeNode* root, int k) {
        count = k;
        DFS(root);
        return ret;
    }

    void DFS(TreeNode* root)
    {
        if(root == nullptr) return;
        if(count > 0) DFS(root->left);
        if(count == 1) ret = root->val;
        --count;
        if(count > 0) DFS(root->right);
    }
};

2.6 二叉树的所有路径

题目链接

257. 二叉树的所有路径 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<string> ret;
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        DFS(root, "");
        return ret;
    }
    void DFS(TreeNode* root, string str)
    {
        if(root == nullptr) return;
        str+=to_string(root->val);
        if(root->left==nullptr && root->right==nullptr)
        {
            ret.push_back(str);
            return;
        }
        else
            str+="->";
        DFS(root->left, str);
        DFS(root->right, str);
    }
};

2.7 全排列

题目链接

46. 全排列 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    bool used[6];
public:
    vector<vector<int>> permute(vector<int>& nums) {
        DFS(nums);
        return ret;
    }
    void DFS(const vector<int>& nums)
    {
        if(path.size() == nums.size())
        {
            ret.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); ++i)
        {
            if(!used[i])
            {
                path.push_back(nums[i]);
                used[i] = true;
                DFS(nums);
                //回溯恢复现场
                path.pop_back();
                used[i] = false;
            }
        }
    }
};

2.8 子集

题目链接

78. 子集 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        DFS(nums, 0);
        return ret;
    }
    //解法一:
    void DFS(const vector<int>& nums, int i)
    {
        //当遍历到叶子时,才能返回结果
        if(i == nums.size())
        {
            ret.push_back(path);
            return;
        }
        //选
        path.push_back(nums[i]);
        DFS(nums, i+1);
        path.pop_back(); //恢复现场
        //不选
        DFS(nums, i+1);
    }
    //解法二:
    void DFS(vector<int>& nums, int pos)
    {
        ret.push_back(path); //进入递归时的path就是一个子集
        for(int i = pos; i<nums.size(); ++i)
        {
            path.push_back(nums[i]);
            DFS(nums,i+1); //要从下一个位置开始选下一个数
            path.pop_back(); //恢复现场
        }
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1805480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hcache缓存查看工具

1、hcache概述 hcache是基于pcstat的&#xff0c;pcstat可以查看某个文件是否被缓存和根据进程pid来查看都缓存了哪些文件。hcache在其基础上增加了查看整个操作系统Cache和根据使用Cache大小排序的特性。官网:https://github.com/silenceshell/hcache 2、hcache安装 2.1下载…

数据又错了-深读实证01

以后我会经常发一些随手写成的“深读实证”&#xff0c;将书稿中的一两个知识点进行展开介绍。 这是第一篇深读实证&#xff0c;涉及的书中知识点有&#xff1a; 我是严肃科普&#xff0c;别夸我观点鲜明&#xff0c;那都是真事&#xff0c;不是观点。云厂商还有大量优化运营提…

深度强化学习+大模型综述Survey on Large Language Model-Enhanced Reinforcement Learning

论文地址&#xff1a;[2404.00282] Survey on Large Language Model-Enhanced Reinforcement Learning: Concept, Taxonomy, and Methods (arxiv.org) 摘要 对 LLM 增强 RL 中现有文献进行了全面的回顾&#xff0c;并总结了其与传统 RL 方法相比的特征&#xff0c;旨在阐明未…

【Linux高级IO】select、poll、epoll

【Linux高级IO】select、poll、epoll toc 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2024.6.5 前言&#xff1a;本篇博客将会介绍面试重点考察的select、poll、epoll IO: input && Output read && write 应用层read&&write的时候&#xff0c…

nest入门教程

1.介绍&#xff1a; Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用的框架。它使用渐进式 JavaScript&#xff0c;构建并完全支持 TypeScript&#xff08;但仍然允许开发者使用纯 JavaScript 进行编码&#xff09;并结合了 OOP&#xff08;面向对象编程&am…

LLM技术

LLM 是利用深度学习和大数据训练的人工智能系统&#xff0c;专门设计来理解、生成和回应自然语言。这些模型通过分析大量的文本数据来学习语言的结构和用法&#xff0c;从而能够执行各种语言相关任务。以 GPT 系列为代表&#xff0c;LLM 以其在自然语言处理领域的卓越表现&…

【Node.js快速部署opencv项目】图像分类与目标检测

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

Java Web学习笔记22——前端工程化

实际的前端开发&#xff1a; 前端工程化&#xff1a;是指在企业级的前端项目开发中&#xff0c;把前端开发所需的工具、技术、流程、经验等进行规范化、标准化。 环境准备&#xff1a; vue-cli&#xff1a; 介绍&#xff1a;vue-cli是Vue官方提供的一个脚手架&#xff0c;用于…

推荐云盘哪个好,各有各的优势

选择合适的云盘服务是确保数据安全、便捷分享和高效协作的关键。下面将从多个维度对目前主流的云盘服务进行详细的对比和分析&#xff1a; 速度性能 百度网盘青春版&#xff1a;根据测试&#xff0c;其上传和下载确实不限速&#xff0c;但主要定位是办公人群&#xff0c;适用于…

STM32快速入门(ADC数模转换)

STM32快速入门&#xff08;ADC数模转换&#xff09; 前言 ADC数模转换存在的意义就是将一些温度传感器、各自数据传感器产生的模拟信号转换成方便识别和计算的数字信号。 导航 图24 通用定时器框图&#xff1a; 图片截取自STM32 F1XX中文参考手册。还是以框图为中心&#x…

MySQL—多表查询—标量子查询

一、引言 上篇学习完子查询的概念和分类。 现在来学习第一种子查询——标量子查询。 &#xff08;1&#xff09;标量子查询的基本概念 子查询返回的结果是单个值&#xff0c;也就是一行一列&#xff08;可以是数字、字符串、日期等&#xff09; 是一种最简单的子查询形式&am…

Go 语言的函数详解:语法、用法与最佳实践

在 Go 语言的世界里&#xff0c;函数是构建和维护任何应用程序的基石。不仅因为它们提供了一种将大问题划分为更小、更易管理部分的方法&#xff0c;而且还因为它们在 Go 程序中扮演着至关重要的角色。从简单的工具函数到复杂的系统级调用&#xff0c;理解和利用 Go 的函数特性…

论文阅读:All-In-One Image Restoration for Unknown Corruption

发表时间&#xff1a;2022 cvpr 论文地址&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/Li_All-in-One_Image_Restoration_for_Unknown_Corruption_CVPR_2022_paper.pdf 项目地址&#xff1a;https://github.com/XLearning-SCU/2022-CVPR-AirNet 在本文…

Mysql使用中的性能优化——索引对插入操作的性能影响

当我们往表中插入数据时&#xff0c;如果表中有索引&#xff0c;则会给插入操作增加更多的工作量。带来的好处是可以提升查询效率。但是这种优劣该如何权衡&#xff0c;则需要通过数据对比来提供佐证。本文我们将对比没有索引、有一个普通索引、有一个唯一索引的性能差距。 结…

UniAnimate:华科提出人类跳舞视频生成新框架,支持合成一分钟高清视频

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

堆排序讲解

前言 在讲堆的删除时&#xff0c;我们发现一步一步删除堆顶的数据&#xff0c;排列起来呈现出排序的规律&#xff0c;所以本节小编将带领大家进一步理解堆排序。 1.堆排序概念 那么什么是堆排序&#xff1f; 堆排序&#xff08;Heap Sort&#xff09;是一种基于堆数据结构的排…

如何从 Android 图库中恢复误删除的照片

如果您正在阅读这篇文章&#xff0c;那么您肯定意外地从 Android 设备中删除了照片。并且您正在寻找一种简单的方法来恢复 Android 图库中已删除的照片。 从图库恢复已删除的照片 随着技术的进步&#xff0c;现在使用单个设备&#xff08;即 Android 手机&#xff09;&#xf…

vue27:脚手架详细介绍main.js

在 Vue.js 中&#xff0c;render 函数是一个可选的选项&#xff0c;它允许你自定义组件的渲染逻辑。 如果你没有在 Vue 实例中提供 render 函数&#xff0c;Vue 将使用模板&#xff08;template&#xff09;来生成虚拟 DOM。 以下是render / template 两种方式的比较&#…

C++ Qt实现http url启动本地应用程序

更多Qt文章,请访问《深入浅出C++ Qt开发技术专栏》:https://blog.csdn.net/yao_hou/category_9276099.html 文章目录 1、注册自定义协议2、编写web页面3、编写C++应用程序我们在使用腾讯会议时经常会通过http链接打开本地的腾讯会议,例如下图: 打开会议发起人给的链接,会出…

Python代码大使用Paramiko轻松判断文件类型,提取上级目录

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、Paramiko简介 Paramiko是一个用于SSHv2协议的Python实现&#xff0c;提供了客户端和服务器功能。它可以用于远程连接和管理服务器&#xff0c;执行命令、上传下载文件等。本文将介绍如何使用Paramiko判断文件类…