前言
前端新人第一次写文章 (整活),半娱乐性质文章,写了很久呢,望大家多包涵(轻喷,俺玻璃心)~
孩子算法老是记不住,比如连「二叉树 」的「递归前序遍历」都记不住怎么写,面试又怕不小心写错,于是我衍生出了一个想法,能不能采用游戏短剧的方式来把算法具像化。
特别是对于前端而言,面试里算法很少,都是常见题,我们更加需要会写这些题!
果然,我现在满脑子都是二叉树,再也不怕记不住算法了! 以前序遍历来说,别再去记什么「中左右」之类的,哪有什么「中」,个人感觉其实是不对的,应该叫「处理当前,先左后右」。
本文讲述了「阿尔萨斯」通过「递归」+「前序遍历」的方式来打败「食尸鬼二叉树」,最后却因得不到「点赞」饿晕在路边的故事。

斥候来报,发现!食尸鬼二叉树!
某日,洛丹伦城外发现一颗「食尸鬼二叉树」。

「阿尔萨斯」当即表示从未听过什么「食尸鬼二叉树」。

那其实「食尸鬼二叉树」就是由若干个「食尸鬼节点」构成的。每个「食尸鬼节点」屁股的左边或者右边都连着另外一个「食尸鬼节点」,也可能没有连,就像下面这样。

不就清理食尸鬼吗,小菜一碟!
但「泰瑞纳斯」似乎想把这次的试炼作为对「阿尔萨斯」智慧的磨练。

阿尔萨斯:我******


冲突!激战食尸鬼二叉树!
「阿尔萨斯」来到城外,巧遇「神秘持剑男」。
「神秘持剑男」教会了「阿尔萨斯」「镜像」技能。

食尸鬼二叉树长这样

「阿尔萨斯」通过兵书知道了什么叫作「前序遍历」,无非就是牢记三个步骤:
- 打倒面前的食尸鬼;
- 跑去左边看看有没有食尸鬼;
- 再跑去右边看看有没有食尸鬼。

「阿尔萨斯」立刻来到食尸鬼面前开始行动,按照兵法所说,先打败面前的食尸鬼。

接着,「阿尔萨斯」使用刚刚偷学的「镜像」分出了2个「阿尔萨斯」,以及达拉然最新科技「电话」去 call 「左边」的分身,问他食尸鬼清理完了吗?
分身看到自己面前有一只「食尸鬼」,不敢妄下定论,继续重复兵法里的步骤,先打败面前的食尸鬼,然后分身也再次使用镜像,派遣新的分身去左边看看有无「食尸鬼」。

那有人就问了,为什么这个分身要使用镜像呢?因为对于「食尸鬼二叉树」来说,只要当前位置有「食尸鬼」,那就说明它的屁股左边有 或者没有食尸鬼,那么就必须再派新的分身去探查。
那如果探查完发现面前没有食尸鬼了,说明这里就安全了,分身的使命就完成啦,可以消失咯~
左边的分身任务完成了,就可以开始给右边的分身「打电话」了,右边的分身也是重复一样的步骤。

一直以此类推

最终「阿尔萨斯」就消灭了全部的食尸鬼。

那代码怎么写呢?
我们先来打开 leetcode 144题「二叉树的前序遍历」

首先,「泰瑞纳斯」给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼」的位置。
javascript
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
// root 相当于食尸鬼二叉树里,第一个食尸鬼的位置
// 那么「泰瑞纳斯」首先给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼的」位置
call(root)
};
那我们来看看打完电话要干什么呢?第一步,干掉食尸鬼!
javascript
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
const bag = [] // New: 这是用来收集食尸鬼的背包
function call(node) {
bag.push(node.val) // New: 第一步,干掉食尸鬼,就把它装进我们的包包里吧~
}
call(root) //「泰瑞纳斯」首先给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼的」位置
};
第二步,派分身去左边探路,给他打电话,让他处理掉那边的食尸鬼。
javascript
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
const bag = [] // 这是用来收集食尸鬼的背包
function call(node) {
bag.push(node.val) // 第一步,干掉食尸鬼,就把它装进我们的包包里吧~
call(node.left) // New: 第二步,派分身去左边探路,给他打电话
}
call(root) //「泰瑞纳斯」首先给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼的」位置
};
第三步,派分身去右边探路,也给他打电话,让他处理掉那边的食尸鬼。
javascript
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
const bag = [] // 这是用来收集食尸鬼的背包
function call(node) {
bag.push(node.val) // 第一步,干掉食尸鬼,就把它装进我们的包包里吧~
call(node.left) // 第二步,派分身去左边探路,给他打电话
call(node.right) // New: 第三步,派分身去右边探路,给他打电话
}
call(root) //「泰瑞纳斯」首先给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼的」位置
};
最后,发现没有食尸鬼任务就结束啦~,装着满包的食尸鬼回去交任务吧!
javascript
/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function(root) {
const bag = [] // 这是用来收集食尸鬼的背包
function call(node) {
if (node == null) return // New: 没有食尸鬼就啥都不用干
bag.push(node.val) // 第一步,干掉食尸鬼,就把它装进我们的包包里吧~
call(node.left) // 第二步,派分身去左边探路,给他打电话
call(node.right) // 第三步,派分身去右边探路,给他打电话
}
call(root) //「泰瑞纳斯」首先给「阿尔萨斯」打电话,告诉了他第一只「食尸鬼的」位置
return bag // New: 回家交差!
};
通过上面这段代码,大家可以发现,在第二步的时候,打电话给分身也会重复执行一样的步骤,实现了递归,也就是一定要左边的「食尸鬼」全部被清理完成后,才会处理右边的「食尸鬼」。
结语
大家喜欢的话,下期尝试来用迭代法做一下中序遍历二叉树吧?感觉迭代法做中序很多小伙伴也是头疼诶!
不知道大家有没有把二叉树的「递归」+「前序遍历」牢记于心了呢?再回忆一遍步骤
- 没有食尸鬼就回家;
- 打倒面前的食尸鬼,装进包包里;
- 打电话给左边看看有没有食尸鬼;
- 打电话给右边看看有没有食尸鬼。
洛丹伦的平静离不开「阿尔萨斯」的努力,让我们一起说,「谢谢你,阿尔萨斯」!
对了,「阿尔萨斯」悄悄跟我说他想吃烤肉,现在已经饿晕过去了,看在「阿尔萨斯」这么努力的份上,大家帮帮他吧!

另外,B站还有视频版哦(全是本人配音,包括兽人语,没有用AI语音哈!),更加容易理解。输入框搜索「魔兽学霸」就可以看到了哦~ 求求各位大佬们有币的捧个币场,有赞的捧个赞场,要是是能评论+关注一下我可爱死你们啦~
链接在此:www.bilibili.com/video/BV1Yi...
