【C++】递归,搜索与回溯算法入门介绍和专题一讲解

简介: 【C++】递归,搜索与回溯算法入门介绍和专题一讲解

一、名词解释

1、什么是递归?

递归就是函数自己调用自己。


2、为什么会用到递归?

递归的本质是:

主问题:—>相同的子问题

子问题:—>相同的子问题

3、如何理解递归?

通过:

  • 1)通过递归的细节展开图(前期可以,过了前期一定不能再用了)
  • 2)通过二叉树中的题目
  • 3)宏观看待递归问题(重要)

越往后学越发现,如果只抓住递归的细节展开图,你会发现你根本就学不好递归这个东西,递归的细节展开图只是为了辅助你读过新手期,如果你后面还在用它,那么你往往是学不好递归的。

那么:如何理解宏观看待递归问题这个点呢?

可以分为几个部分:

  • 1)不要再在意递归的细节展开图
  • 2)把递归的函数当成一个黑盒子
  • 3)相信这个黑盒子一定能完成这个任务

4、如何写好递归?

写好一个递归也分为三点:

  • 1)先找到相同的子问题(函数头的设计)
  • 2)只关心某一个子问题是如何解决的(函数体的书写)
  • 3)递归出口

二、搜索vs深度优先遍历vs深度优先搜索vs宽度优先遍历vs宽度优先搜索vs暴搜

1、深度优先遍历vs深度优先搜索

其实,一句话就能概括下来:

遍历是形式,搜索是目的。

所以,我们平时说的深度优先遍历和深度优先搜索,其实他们俩是一样的。

都可以叫做dfs

2、宽度优先遍历vs宽度优先搜索

其实,一句话就能概括下来:

遍历是形式,搜索是目的。

所以,我们平时说的宽度优先遍历和宽度优先搜索,其实他们俩是一样的。

都可以叫做bfs

3、关系图

我们所说的搜索,其实就是暴搜。

4. 搜索问题的拓展

我们刚开始学习搜索时,总以为dfsbfs这两个搜索都只与二叉树有关。其实不然。

从下面的例题开始你会发现,很多东西都能使用dfs进行求解。

三、回溯与剪枝

这两个名词听起来貌似很高大上,其实用一个例子就能解释清楚了。

下面来看一个迷宫问题:

入口和出口如上:我们从入口出发,往右边走遇到墙壁之后,往下走。走到蓝色标记,也就是拐角点的地方后,这就是一个岔路口,此时我们有两种选择:

  • 1)往左边走
  • 2)往右边走

当我们选择往左边走时,如下图:

会遇到墙壁,此时我们就需要原路返回

这个从某一位置出发,一条道走到黑,再沿着原路返回的过程,就叫做回溯

回溯的这条路径,我们用绿色来标记。

此时又走到了蓝色拐点,在这个岔路口我们有三种选择:

1)往上走

2)往左走

3)往右走

可是,我们最初是从上面下来的,然后沿着左边走,走不通之后再返回来的。

所以,我们只有一个选择:往右走。

而这个判断的过程,也就是选择路径的过程,就叫做剪枝。

将往上走的路径剪掉,将往左走的路径剪掉,就是剪枝。

四、专题一

1. 汉诺塔问题

点我直达

算法分析

1.找到相同的子问题:


当n = 1时:

直接将盘子从A柱子挪到C柱子即可。


当n = 2 时

分为三步走:

1)我们需要将盘子a上面的盘子借助C柱子移动到B柱子。

2)将a盘子移动到C柱子上

3)将B柱子上的所有盘子借助A盘子移动到C柱子上。


当n = 3 时

与第二步相同:

分为三步走

1)将a盘子上面的所有盘子借助C柱子移动到B柱子上。

2)将a盘子移动到C柱子上。

3)将B柱子上面的所有盘子借助A柱子移动到C柱子上。

2.只关心某一个子问题如何解决。

所以我们会发现,当n >= 2时,都会执行相同的子问题的操作。操作如下:

  • 1)将a盘子上面的所有盘子通过C柱子挪到B柱子上。
  • 2)将a盘子挪到C盘子上。
  • 3)将B柱子上面的所有盘子挪到C柱子上。

在这整个过程中,你要相信一件事情:

你交给dfs这个函数的任务是:

我要把所有盘子全部借助一个柱子挪到另一个柱子上。

并且要相信dfs这个函数一定能完成这个任务。

这就是宏观看待问题的思路。

3.递归出口

递归出口就是当n = 1时,你会发现跟当n = 其他数的操作步骤是不一样的。

当n = 1时,直接将a盘子移动到C柱子即可。

代码编写

class Solution {
public:
//1.重复的子问题(函数头)
//要将A柱子上面的所有盘子借助B柱子全部转移到C柱子上面
//2.只关心某一个子问题在做什么(函数体)
//3.递归出口
    void dfs(vector<int>& A, vector<int>& B, vector<int>& C,int n) 
    {
        if(n == 1)
        {
            C.push_back(A.back());
            A.pop_back();
            return;
        }
        dfs(A,C,B,n-1);
        C.push_back(A.back());
        A.pop_back();
        dfs(B,A,C,n-1);
    }
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) 
    {
        int n = A.size();
        dfs(A,B,C,n);
    }
};

总结

提示:这里对文章进行总结:

本文章详细讲解了递归,搜索与回溯算法的入门理解级操作,以及通过一道例题感受一下dfs这种算法的强大之处,关键在于dfs写起来特别简单。

学好dfs,是进入大厂的必备技能。

相关文章
|
6月前
|
算法 数据可视化 测试技术
HNSW算法实战:用分层图索引替换k-NN暴力搜索
HNSW是一种高效向量检索算法,通过分层图结构实现近似最近邻的对数时间搜索,显著降低查询延迟。相比暴力搜索,它在保持高召回率的同时,将性能提升数十倍,广泛应用于大规模RAG系统。
541 10
HNSW算法实战:用分层图索引替换k-NN暴力搜索
|
6月前
|
存储 算法
算法入门:专题二---滑动窗口(长度最小的子数组)类型题目攻克!
给定一个正整数数组和目标值target,找出总和大于等于target的最短连续子数组长度。利用滑动窗口(双指针)优化,维护窗口内元素和,通过单调性避免重复枚举,时间复杂度O(n)。当窗口和满足条件时收缩左边界,更新最小长度,最终返回结果。
|
6月前
|
存储 算法 编译器
算法入门:剑指offer改编题目:查找总价格为目标值的两个商品
给定递增数组和目标值target,找出两数之和等于target的两个数字。利用双指针法,left从头、right从尾向中间逼近,根据和与target的大小关系调整指针,时间复杂度O(n),空间复杂度O(1)。找不到时返回{-1,-1}。
|
6月前
|
存储 算法
算法入门:专题一:双指针(有效三角形的个数)
给定一个数组,找出能组成三角形的三元组个数。利用“两边之和大于第三边”的性质,先排序,再用双指针优化。固定最大边,左右指针从区间两端向内移动,若两短边之和大于最长边,则中间所有组合均有效,时间复杂度由暴力的O(n³)降至O(n²)。
|
7月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
357 5
|
7月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
254 0
|
7月前
|
存储 算法 数据可视化
基于禁忌搜索算法的TSP问题最优路径搜索matlab仿真
本程序基于禁忌搜索算法解决旅行商问题(TSP),旨在寻找访问多个城市的最短路径。使用 MATLAB 2022A 编写,包含城市坐标生成、路径优化及结果可视化功能。通过禁忌列表、禁忌长度与藐视准则等机制,提升搜索效率与解的质量,适用于物流配送、路径规划等场景。
|
8月前
|
机器学习/深度学习 并行计算 算法
MATLAB实现利用禁忌搜索算法解决基站选址问题
MATLAB实现利用禁忌搜索算法解决基站选址问题
252 0
|
9月前
|
机器学习/深度学习 数据采集 算法
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
198 0