【算法基础】深度优先搜索(DFS)

本文介绍了深度优先搜索(DFS)算法,包括其原理、递归实现方法,以及如何在二叉树的前序遍历和最大深度问题中应用。通过LeetCode题目实例展示了DFS在解决这类问题中的作用。
摘要由CSDN通过智能技术生成

1 定义

深度优先搜索(Depth-First Search,DFS),是一种通过暴力枚举每一条路径的方法,来遍历树或图的所有路径,其中,每个节点只能访问一次。DFS通常是由递归来实现的,可以用来处理遍历整张图、求问题有多少个解、多少个节点、多少条路经等。可理解为是一种“一条路走到黑”的算法,最糟糕的时间复杂度可达到O(n!)。

2 算法思想

回溯法:也可以称为试探法,程序按照优选条件向前探索,但是在到达某一结点时,发现该节点并不是最优解,故此时就要回退一步或多步重新选择节点,这样回退重选的过程称为回溯

3 具体步骤

1 创建结果储存变量,初始化当前结果;

2 设计递归函数

        -如达到结果,则返回(basecase)

        -如未达到结果,则更新当前结果

        -对当前节点使用该递归函数

3 开始调用递归函数

模板代码:

int check(参数)
{
    if(满足条件)        //basecase
        return 1;
    return 0;
}
 
void dfs(int step)
{
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件
               标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)
        }
}   

4.1 例题1

【leetcode-144】给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

4.1.1大致思路

二叉树的前序遍历指的是按照访问根节点——左子树——右子树的方式遍历这棵树。以上图为例,遍历的结果就是:1 2 4 5 7 3 6

我们在访问左子树或右子树的时候,我会用到同样的方式来遍历,这似乎是一个“循环”,(即让计算机重复相同的操作),直到遍历到这棵树的叶节点,所有,我们可以使用递归来实现遍历。

定义 preorder(root) 表示当前遍历到 root 节点的答案。按照定义,我们只要首先将 root 节点的值加入答案,然后递归调用 preorder(root.left) 来遍历 root 节点的左子树,最后递归调用 preorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点

4.1.2 代码实现

class Solution {
public:
    void preorder(TreeNode *root, vector<int> &res) {
        if (root == nullptr) {        //basecase
            return;
        }
        res.push_back(root->val);
        preorder(root->left, res);
        preorder(root->right, res);
    }

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        preorder(root, res);
        return res;
    }
};

4.2 例题2

【leetcode-104】给定一个二叉树 root ,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

4.2.1 大致思路

如果我们分别知道该二叉树的左子树和右子树的最大深度l、r,那么该二叉树的最大深度为max(l,r)+1 。后面的那个1是root节点本生的长度。

而左子树和右子树的最大深度又可以以同样的方式进行计算。因此我们可以用「深度优先搜索」的方法来计算二叉树的最大深度。

4.2.2 代码实现

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;            //basecase
        return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }
};

5 一些个人理解(仅代表个人观点,欢迎指出错误)

对于递归,我们可以将它理解为一个全自动帮程序员处理数据的手段,也就是说,你遇到了什么问题,交给递归,它会帮你刨根溯源,在这里,怎么样才算是刨到了根呢?这就体现出basecase的重要性了。没有basecase,这个递归就只有“递”,不会“归”。

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值