贰.1.5 实战:字节跳动前端面试2道算法题

有关数组和二叉树的题高频出现

笔者在写作本书期间,曾经受邀参加字节跳动北京地区的“WEB前端高级工程师”岗位的面试。面试官是一位前端小姐姐,女程序员在其他公司很少见,所以觉得字节跳动的极客文化很有特色。一番流程性的自我介绍之后,小姐姐提了两道笔试算法题。

贰.1.5.1 多维数组扁平化

题目

原数组[[0],[2,3,4],1,[1,[2,3]]],写一段代码,将该数组扁平化,输出[0,2,3,4,1,1,2,3]

分析

如果读过本书壹.1.1 新版 ECMAScript 特性分析,就会发现 ES10 最新的特性Array.prototype.flat()可以完美解题,但是考虑到这个新特性是2019年(面试时)才出来不久,很多浏览器没有支持这个特性,所以也要考虑用原生JavaScript代码来实现这个扁平化数组的功能。

既然是处理数组,那就要熟悉JavaScript数组对象的各种方法,并恰当的利用它们来实现我们的目的。

解法一

请认真阅读注释,很多关键性提示都在注释里面详细指出了。

(() => {
    //题目中给的测试数据
    let sourceArr = [[0], [2, 3, 4], 1, [1, [2, 3]]];
    //结果数组,用来保存最终输出的数据
    let resultArr = [];

    (function doFunc(arr) {
        //若无子数组,直接把arr的数据导入结果数组resultArr
        if (!hasChildArray(arr)) {
            //用concat方法,将resultArr与arr合并后再返回给resultArr
            resultArr = resultArr.concat(arr);
        }
        //若有子数组
        else {            
            for (let i = 0, l = arr.length; i < l; i++) {
                //如果子元素类型是数字
                if (typeof arr[i] == "number") {
                    resultArr.push(arr[i]); //放入结果数组中保存起来
                }
                //否则,如果子元素类型是数组
                else if (Array.isArray(arr[i])) {
                    doFunc(arr[i]); //递归调用
                }
            }
        }
    })(sourceArr);

    console.log(resultArr); //>> [0, 2, 3, 4, 1, 1, 2, 3]

    /**
     * 定义一个工具性子函数,判断参数中传来的数组是否有子数组
     * @param   {Array}   数组
     * @return  {Boolean} true:有;false:没有
     */
    function hasChildArray(arr) {
        /*
        arr.some() 方法测试数组arr中是不是有元素通过了被提供的函数callback
        的测试。它返回的是一个Boolean类型的值。只要数组中有元素通过callback的
        测试就会返回true;所有元素都没有通过callback的测试,返回值才会为false。
        */
        return arr.some(function callback(item) {
            //判断arr中的子元素item是否数组
            if (Array.isArray(item)) {
                return true; //返回true表明通过了测试,让外层some也返回true
            }
        });
    }
})();

解法二

这个解法是后来补充的,面试时并没有想出来,后来觉得挺简洁的,所以分享出来。

贰.1.5.2 二叉树&完整路径和

经过上面的数组算法题热身之后,小姐姐比较满意,还想继续验证一下笔者在数据结构和算法这块儿的基本功,于是喝了一口茶之后,她紧接着出了一个更开放性的、二叉树有关的题。

题目

对于给定的二叉树,判断是否存在一条完整路径(从根节点开始,到叶节点结束的连线),其路径上节点的值之和为target,输出布尔值。举例:下面的树,是否存在一条完整路径,该路径上各个节点之和target=7?

分析

这个题目出得确实很开放,如果对树、二叉树的概念不熟悉,会有点无从下手,好在我们已经经过二叉树相关的学习训练了。开放性命题需要做一些假设,把前提条件确定了,才能解题。先确定树、结点的数据结构,有什么样的数据结构,就有后面什么样的算法。二叉树的遍历,离不开递归。

解法一

笔者多年的OOP经(毒)验(素)派上用场了,首先就会想到用两个类定义树和结点,然后写一个递归遍历树,代码如下:

看到笔者很快交出了答案,面试官小姐姐嘴角露出了一丝微笑。经过大概1分钟的review之后,她说:“二叉树BTree和结点Node本质上可以是相同的数据结构的,根结点其实就可以代表一棵树了,你可仔细想想。你的答题虽然实现了目的,但是不需要定义2个类来分别放树和结点,能否精简一下呢?”

的确,她说的对,完全可以精简。如果要求树和结点的数据结构一样,那可以考虑用数组的形式来表示它们,用多维数组来代表一颗二叉树即可,于是有了第二种解法。

解法二

面试官小姐姐很满意,在填写面试评估的那一栏里写下了“通过技术面试”。

贰.1.5.3 本篇结语

由此可见,在一线互联网公司面试,碰到数据结构和算法这块儿的面试题是避免不了的,而且考的是触类旁通,题目都是基础数据结构和算法的变体,所以更要扎扎实实把最常见的数据结构和算法题研究熟悉,你一定可以顺利通过技术面试。

最后更新于

这有帮助吗?