dfs和递归

最近写了一些递归的题目,但是总觉得不够直观。

一件事分开干重复下去总能干完。

//一棵树的中序遍历
void dfs(TreeNode* root){
    if(!root) return ;
    if(root->left) dfs(root->left);
    visit(root);
    if(root->right) dfs(root->right);
}

再比如:

// 543. 二叉树的直径
class Solution {
public:
    int depth(TreeNode* root){
        if(root==NULL) return 0;
        return max(depth(root->left),depth(root->right))+1;
    }
    int diameterOfBinaryTree(TreeNode* root) {
        if(root==NULL) return 0;
//         分为三种情形,一,在左子树取得最大。二、在右子树取得最大。三、跨过根节点取得最大
        return max(max(diameterOfBinaryTree(root->left),diameterOfBinaryTree(root->right)),
                   depth(root->left)+depth(root->right));
                   //注意这里的分支数比depth小一,加二减二抵消了
    }
};

我从来是一个很笨的人,什么事情不动手,亲自做一做,便总是想不通,符号语言在我眼里必须变成直观的才行。

所以,递归解释为自己调用自己让我摸不着头脑。总觉得还是不够直观。

先从一个简单的例子说明白什么叫直观:

我小时候有一个光荣的工作:厨房购物小能手。比如常常要买柴米油盐了。

今天妈妈再一次在炒菜的时候没有盐了,于是妈妈面前有了一个问题如何得到盐?

于是妈妈把钱教给我,让我解决问题。

我想这个问题不就是上网订购么?三下五除二京东下了单。

之后商店的盐有了,只是还没有到我手里,后来,我等了半天,快递小哥送了一箱盐到我家。

我呢,马上把盐交给母亲大人。

这之中是怎么解决问题的呢?

// 妈妈买盐->我买盐->商店提供盐->快递给我->我交给妈妈
bool buy_salt(people){
	if(store_has_salt) return true;
	return buy_salt(next_people);
}

这时候似乎说明了一些问题:

这里面的人仅仅做了运输的作用,像一条U型线。或者叫回旋镖。只不过着这里在天上飞着的是一箱盐,前半段是虚线,表示请求还不知道具体有没有,到顶点,明白可行于是变成实线。

所以,这是一种玄学的回归,虚实相映,又像太极里面的金刚倒锥,前面似乎在蓄力,到顶点一锤定音。

到这里似乎这是一种聪明的思维方法:我不会,可以问问下一个人会不会?总有一天会遇到一个懂的人,把我们这群笨人,依次传递教会到我这里。

这是一种领导作风,举重若轻,自信下面人一定可以做到,我只要发方案就行了。

明白了做领导的感觉可以试验做一道题:


https://leetcode-cn.com/problems/friend-circles/description/

班上有 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

示例 1:

输入: 
[[1,1,0],
 [1,1,0],
 [0,0,1]]
输出: 2 
说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
第2个学生自己在一个朋友圈。所以返回2。

有几个朋友圈,专业一点叫有几个联通子图。乍一听,依然如此抽象,上来就是模式和概念,失去了直观性的体验,同时又变得难以理解。同样的,我们把问题摆到眼前,怎么来解决?

当然,你可能下意识觉得我不会,这样很好!你可以做一回领导,把球丢出去,让会做的人做。听起来挺好的,实际上呢?也的确如此!

为了避免失误,你大可以在你认识的人里可以广播:

不断联系认识的,朋友圈扩张到不能再扩大时,恭喜你找到一个。

然后,告知领导即可。有领导判断是不是重复了之类的小问题,看到问题扩散之后变得可以解决了。

  void ask_someone_i_know(me){
        while(each_one_mylist){//把我认识的人完全骚扰一遍
            if(find_one_friend){
                this_friend had visited;
                ask_someone_i_know(my_friend);
            }
        }
        return;
    }

   int findCircleNum(){
        int ans=0;//计数
        for(everyone){
            if(he not be visited){
                ask_someone_i_know(he);//把他认识的人都询问一遍
                ans++;
            }
        }
        return ans;
    }

于是对话如下:

领导:小王你认识的人都给问问,我看看有几个圈子

小王:哦

领导:小李你认识的人也给问问,你是不是也有个圈子

小李:我和小王是一个圈子的

领导:走走走,下一个……

这一次,也是扔回旋镖,只不过是多个人分别扔而已,看最后落到手里的有几个。

这一次怎么直观的看到过程的发展呢?

注意到这里很像一种小时候玩的游戏,在河里丢石子,之后产生的波纹效果。

我像自己认识的人(A或B)中丢出一个飞镖,被自己认识的人继续像他认识的人丢出去,形成扇形的扩散效应。由于计算时候是一个一个来的看出来就好像是这样:

这就是dfs的一种直观的运行路线,像是递归的扩展(在维度上),不再只向一个人求助,每个人都可以有些求助的对象,于是依次求助之后,就像五指山一样,有高有低,但是必须从山脚走上山,然后回到山脚再上山,即是所谓的深度优先。


递归:回旋镖;前虚后实;

dfs:    由一群人接力扔飞镖,在每一层飞行中添加一些讯息,直到不能再丢(到达没有人的地方(最深的地方))时候飞镖返回。

发布了27 篇原创文章 · 获赞 1 · 访问量 1437

猜你喜欢

转载自blog.csdn.net/qq_34890856/article/details/82431782
今日推荐