面试了十几个高级前端,竟然连(扁平数据结构转Tree)都写不出来

招聘季节一般都在金三银四,或者金九银十。最近在这五六月份,陆陆续续面试了十几个高级前端。有一套考察算法的小题目。后台返回一个扁平的数据结构,转成树。

我们看下题目:打平的数据内容如下:

let arr = [
    {id: 1, name: '部门1', pid: 0},
    {id: 2, name: '部门2', pid: 1},
    {id: 3, name: '部门3', pid: 1},
    {id: 4, name: '部门4', pid: 3},
    {id: 5, name: '部门5', pid: 4},
]
复制代码

输出结果

[
    {
        "id": 1,
        "name": "部门1",
        "pid": 0,
        "children": [
            {
                "id": 2,
                "name": "部门2",
                "pid": 1,
                "children": []
            },
            {
                "id": 3,
                "name": "部门3",
                "pid": 1,
                "children": [

                ]
            }
        ]
    }
]
复制代码

我们的要求很简单,可以先不用考虑性能问题。实现功能即可,回头分析了面试的情况,结果使我大吃一惊。

10%的人没思路,没碰到过这种结构

60%的人说用过递归,有思路,给他个笔记本,但就是写不出来

20%的人在引导下,磕磕绊绊能写出来

剩下10%的人能写出来,但性能不是最佳

感觉不是在招聘季节遇到一个合适的人真的很难。

接下来,我们用几种方法来实现这个小算法

什么是好算法,什么是坏算法

判断一个算法的好坏,一般从 执行时间占用空间来看,执行时间越短,占用的内存空间越小,那么它就是好的算法。对应的,我们常常用时间复杂度代表执行时间,空间复杂度代表占用的内存空间。

时间复杂度的计算并不是计算程序具体运行的时间,而是算法执行语句的次数。 随着 n的不断 增大,时间复杂度不断 增大,算法 花费时间越多。 常见的时间复杂度有

  • 常数阶 O(1)
  • 对数阶 O(log2 n)
  • 线性阶 O(n)
  • 线性对数阶 O(n log2 n)
  • 平方阶 O(n^2)
  • 立方阶 O(n^3)
  • k次方阶 O(n^K)
  • 指数阶 O(2^n)

通常我们计算时间复杂度都是计算最坏情况。计算时间复杂度的要注意的几个点

  • 如果算法的执行时间 不随n增加增长,假如算法中有 上千条语句,执行时间也不过是一个 较大的常数。此类算法的时间复杂度是 O(1)。 举例如下:代码执行100次,是一个常数,复杂度也是 O(1)
letx = 1
    while (x 复制代码
  • 多个循环语句时候,算法的时间复杂度是由 嵌套层数最多的循环语句中 最内层语句的方法决定的。举例如下:在下面for循环当中, 外层循环每执行 一次内层循环要执行 n次,执行次数是根据n所决定的,时间复杂度是 O(n^2)
for (i = 0
         for (j = 0
             // ...code
         }
     }
复制代码
  • 循环不仅与 n有关,还与执行循环 判断条件有关。举例如下:在代码中,如果 arr[i]不等于 1的话,时间复杂度是O(n)。如果 arr[i]等于 1的话,循环不执行,时间复杂度是 O(0)
for(var i = 0; i[i] !=1; i++) {
    // ...code
    }

复制代码

空间复杂度是对一个算法在运行过程中临时占用存储空间的大小。

计算空间复杂度的简单几点

  • 仅仅只复制单个变量,空间复杂度为O(1)。举例如下:空间复杂度为O(n) = O(1)。
leta = 1
   let b = 2
   let c = 3
   console.log('输出a,b,c', a, b, c)
复制代码
  • 递归实现,调用fun函数,每次都创建1个变量k。调用n次,空间复杂度O(n*1) = O(n)。
functionfun(n) {
       let k = 10;
       if (n == k) {
           return n;
       } else {
           return fun(++n)
       }
    }
复制代码

不考虑性能实现,递归遍历查找

主要思路是提供一个递 getChildren的方法,该方法 递归去查找子集。 就这样,不用考虑性能,无脑去查,大多数人只知道递归,就是写不出来。。。

/**
 * 递归查找,获取children
 */
constgetChildren = (data, result, pid) => {
  for (const item of data) {
    if (item.pid === pid) {
      const newItem = {...item, children: []}
      result.push(newItem)
      getChildren(data, newItem.children, item.id)
    }
  }
}

/**
* 转换方法
*/
const arrayToTree = (data, pid) => {
  const result = []
  getChildren(data, result, pid)
  return result
}

复制代码

从上面的代码我们分析,该实现的时间复杂度为 O(2^n)

不用递归,也能搞定

主要思路是先把数据转成 Map去存储,之后遍历的同时借助 对象的引用,直接从 Map找对应的数据做存储

function arrayToTree(items) {
  constresult = []
  const itemMap = {}

  // 先转成map存储
  for (const item of items) {
    itemMap[item.id] = {...item, children: []}
  }

  for (const item of items) {
    const id = item.id
    const pid = item.pid
    const treeItem =  itemMap[id]
    if (pid === 0) {
      result.push(treeItem)
    } else {
      if (!itemMap[pid]) {
        itemMap[pid] = {
          children: [],
        }
      }
      itemMap[pid].children.push(treeItem)
    }

  }
  return result
}
复制代码

从上面的代码我们分析,有两次循环,该实现的时间复杂度为 O(2n),需要一个Map把数据存储起来,空间复杂度 O(n)

最优性能

function arrayToTree(items) {
  constresult = []
  const itemMap = {}
  for (const item of items) {
    const id = item.id
    const pid = item.pid

    if (!itemMap[id]) {
      itemMap[id] = {
        children: [],
      }
    }

    itemMap[id] = {
      ...item,
      children: itemMap[id]['children']
    }

    const treeItem =  itemMap[id]

    if (pid === 0) {
      result.push(treeItem)
    } else {
      if (!itemMap[pid]) {
        itemMap[pid] = {
          children: [],
        }
      }
      itemMap[pid].children.push(treeItem)
    }

  }
  return result
}
复制代码

从上面的代码我们分析,一次循环就搞定了,该实现的时间复杂度为 O(n),需要一个Map把数据存储起来,空间复杂度 O(n)

小试牛刀

方法1000(条)10000(条)20000(条)50000(条)递归实现154.596ms1.678s7.152s75.412s不用递归,两次遍历0.793ms16.499ms45.581ms97.373ms不用递归,一次遍历0.639ms6.397ms25.436ms44.719ms

从我们的测试结果来看,随着数量的增大,递归的实现会越来越慢,基本成指数的增长方式。

结束语

大家觉得高级前端,该不该很顺利的把这个给写出来。评论区留下你的见解。有比以上更好的实现,评论区留下你的答案,大家一起学习。

如果你觉得该文章不错,不妨

1、 点赞,让更多的人也能看到这篇内容

2、 关注我,让我们成为长期关系

3、关注公众号「 前端有话说」,里面已有多篇原创文章,和开发工具,欢迎各位的关注,第一时间阅读我的文章

Original: https://blog.csdn.net/china_coding/article/details/128392157
Author: china_coding
Title: 面试了十几个高级前端,竟然连(扁平数据结构转Tree)都写不出来

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/777880/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Pytorch+CUDA安装方法步骤

    首先我们要确定本机是否有独立显卡,在右键点击开始按钮—设备管理器-显示适配器中,查看是否有独立显卡。可以看到本机有一个集成显卡和独立显卡NVIDIA GetForce GTX 10…

    Python 2023年8月2日
    039
  • Python读取csv文件

    #导入pandas包并设置别名为pd import pandas as pd #读取csv格式文件并把格式设置为DataFrame格式 #值1是路径可以用绝对路径(cd盘内读取)也…

    Python 2023年8月19日
    039
  • 基于lio-sam框架,教你如何进行回环检测及位姿计算

    摘要:本篇主要解析lio-sam框架下,是如何进行回环检测及位姿计算的。 图优化本身有成形的开源的库,例如 g2o ceres gtsam lio-sam 中就是 通过 gtsam…

    Python 2023年10月29日
    037
  • 利用Python制作本地Excel的查询与生成的程序

    目录 前言 需求 实验步骤 Excel预览图片 查询 追加查询结果到Excel 完整代码 前言 大家好 我是毕加锁(锁!) 今天教大家利用Python制作本地Excel的查询与生成…

    Python 2023年8月7日
    054
  • 要点初见:开源AI绘画工具Stable Diffusion代码分析(文本转图像)、论文介绍(上)

    博主先前整理并简单介绍了AI绘图工具的部署资源与攻略,觉得其中Stable Diffusion部分不够带劲,故开始试图从论文与代码中一探究竟。前文链接如下: 要点初见:AI绘图工具…

    Python 2023年8月1日
    077
  • matplotlib之pyplot模块——绘制茎叶图(杆图)stem()

    当前有效 matplotlib版本为: 3.4.1。 概述 stem()函数的作用是绘制茎叶图(杆图、棉棒图、火柴杆图)。 茎叶图根据基线( baseline)上的位置( locs…

    Python 2023年9月3日
    0110
  • 【国产可编程逻辑控制器plc调研】

    啊哦~你想找的内容离你而去了哦 内容不存在,可能为如下原因导致: ① 内容还在审核中 ② 内容以前存在,但是由于不符合新 的规定而被删除 ③ 内容地址错误 ④ 作者删除了内容。 可…

    Python 2023年11月8日
    034
  • Python

    关于Python安装pip从而下载pygame的有关问题(本人试错经历):1.首先是Python版本的问题选用3.9版本时要选3.92而不是3.902.安装时勾选环境变量path3…

    Python 2023年9月25日
    034
  • android stdio开发抖音自动点赞案例

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Python 2023年6月12日
    066
  • i.MX 6ULL 驱动开发 二十九:向 Linux 内核中添加自己编写驱动

    一、概述 Linux 内核编译流程如下: 1、配置 Linux 内核。 2、编译 Linux 内核。 说明:进入 Linux 内核源码,使用 make help 参看相关配置。 二…

    Python 2023年11月7日
    055
  • Django连接、访问并显示mysql数据库

    首先在mysql中建立数据库,并create table留作备用 记录几个MySQL常用的语句: select database() 显示当前所在的位置(哪个数据库) show d…

    Python 2023年8月3日
    060
  • 网络安全与IP安全

    网络安全 是指网络系统的硬件,软件以及系统中的数据收到的保护。保护的基本属性为:机密性,身份认证,完整性和可用性;基本特征:相对性,时效性,相关性,不确定性,复杂性和重要性。在该方…

    Python 2023年9月15日
    039
  • 莫烦pytorch学习笔记(一)

    numpy与torch一些联系 numpy—->torch转换 使用from_numpy()方法 torch_data=torch.from_numpy(np_d…

    Python 2023年8月26日
    043
  • WSGI规范

    WSGI是一种服务器和应用交流的接口规范。如果一个应用服从于WSGI规范,那么它将能够运行于任何服从WSGI规范的服务器上。WSGI应用可以堆叠,那些处于栈中间位置的称作中间件(m…

    Python 2023年6月12日
    061
  • conda常用指令

    目录 conda基础命令 conda环境管理:创建、切换、删除等 环境软件包的管理:安装、卸载、查看等 conda基础命令 查看conda帮助信息 conda –help //&…

    Python 2023年9月7日
    053
  • 序列类型

    字符串 由很多个字符组成的字符序列,字符串属于 **序列类型 序列简介 数值类型:可以表示 数字,数值 int float bool 序列类型:存储多个数据的数据类型<det…

    Python 2023年5月23日
    087
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球