最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

高級(jí)前端面試手寫扁平數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)Tree

 更新時(shí)間:2022年06月13日 16:59:20   作者:杰出D  
這篇文章主要為大家介紹了高級(jí)前端面試手寫扁平數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)Tree示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

招聘季節(jié)一般都在金三銀四,或者金九銀十。最近在這五六月份,陸陸續(xù)續(xù)面試了十幾個(gè)高級(jí)前端。有一套考察算法的小題目。后臺(tái)返回一個(gè)扁平的數(shù)據(jù)結(jié)構(gòu),轉(zhuǎn)成樹。

我們看下題目:打平的數(shù)據(jù)內(nèi)容如下:

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},
]

輸出結(jié)果

[
    {
        "id": 1,
        "name": "部門1",
        "pid": 0,
        "children": [
            {
                "id": 2,
                "name": "部門2",
                "pid": 1,
                "children": []
            },
            {
                "id": 3,
                "name": "部門3",
                "pid": 1,
                "children": [
                    // 結(jié)果 ,,,
                ]
            }
        ]
    }
]

我們的要求很簡(jiǎn)單,可以先不用考慮性能問(wèn)題。實(shí)現(xiàn)功能即可,回頭分析了面試的情況,結(jié)果使我大吃一驚。

10%的人沒(méi)思路,沒(méi)碰到過(guò)這種結(jié)構(gòu)

60%的人說(shuō)用過(guò)遞歸,有思路,給他個(gè)筆記本,但就是寫不出來(lái)

20%的人在引導(dǎo)下,磕磕絆絆能寫出來(lái)

剩下10%的人能寫出來(lái),但性能不是最佳

感覺(jué)不是在招聘季節(jié)遇到一個(gè)合適的人真的很難。

接下來(lái),我們用幾種方法來(lái)實(shí)現(xiàn)這個(gè)小算法

什么是好算法,什么是壞算法

判斷一個(gè)算法的好壞,一般從執(zhí)行時(shí)間和占用空間來(lái)看,執(zhí)行時(shí)間越短,占用的內(nèi)存空間越小,那么它就是好的算法。對(duì)應(yīng)的,我們常常用時(shí)間復(fù)雜度代表執(zhí)行時(shí)間,空間復(fù)雜度代表占用的內(nèi)存空間。

時(shí)間復(fù)雜度

時(shí)間復(fù)雜度的計(jì)算并不是計(jì)算程序具體運(yùn)行的時(shí)間,而是算法執(zhí)行語(yǔ)句的次數(shù)。

隨著n的不斷增大,時(shí)間復(fù)雜度不斷增大,算法花費(fèi)時(shí)間越多。 常見(jiàn)的時(shí)間復(fù)雜度有

  • 常數(shù)階O(1)
  • 對(duì)數(shù)階O(log2 n)
  • 線性階O(n)
  • 線性對(duì)數(shù)階O(n log2 n)
  • 平方階O(n^2)
  • 立方階O(n^3)
  • k次方階O(n^K)
  • 指數(shù)階O(2^n)

計(jì)算方法

  • 選取相對(duì)增長(zhǎng)最高的項(xiàng)
  • 最高項(xiàng)系數(shù)是都化為1
  • 若是常數(shù)的話用O(1)表示

舉個(gè)例子:如f(n)=3*n^4+3n+300 則 O(n)=n^4

通常我們計(jì)算時(shí)間復(fù)雜度都是計(jì)算最壞情況。計(jì)算時(shí)間復(fù)雜度的要注意的幾個(gè)點(diǎn)

  • 如果算法的執(zhí)行時(shí)間不隨n的增加而增長(zhǎng),假如算法中有上千條語(yǔ)句,執(zhí)行時(shí)間也不過(guò)是一個(gè)較大的常數(shù)。此類算法的時(shí)間復(fù)雜度是O(1)。 舉例如下:代碼執(zhí)行100次,是一個(gè)常數(shù),復(fù)雜度也是O(1)。
    let x = 1;
    while (x <100) {
     x++;
    }
  • 有多個(gè)循環(huán)語(yǔ)句時(shí)候,算法的時(shí)間復(fù)雜度是由嵌套層數(shù)最多的循環(huán)語(yǔ)句中最內(nèi)層語(yǔ)句的方法決定的。舉例如下:在下面for循環(huán)當(dāng)中,外層循環(huán)每執(zhí)行一次,內(nèi)層循環(huán)要執(zhí)行n次,執(zhí)行次數(shù)是根據(jù)n所決定的,時(shí)間復(fù)雜度是O(n^2)。
  for (i = 0; i < n; i++){
         for (j = 0; j < n; j++) {
             // ...code
         }
     }
  • 循環(huán)不僅與n有關(guān),還與執(zhí)行循環(huán)判斷條件有關(guān)。舉例如下:在代碼中,如果arr[i]不等于1的話,時(shí)間復(fù)雜度是O(n)。如果arr[i]等于1的話,循環(huán)不執(zhí)行,時(shí)間復(fù)雜度是O(0)。
    for(var i = 0; i<n && arr[i] !=1; i++) {
    // ...code
    }

空間復(fù)雜度

空間復(fù)雜度是對(duì)一個(gè)算法在運(yùn)行過(guò)程中臨時(shí)占用存儲(chǔ)空間的大小。

計(jì)算方法:

  • 忽略常數(shù),用O(1)表示
  • 遞歸算法的空間復(fù)雜度=(遞歸深度n)*(每次遞歸所要的輔助空間)

計(jì)算空間復(fù)雜度的簡(jiǎn)單幾點(diǎn)

僅僅只復(fù)制單個(gè)變量,空間復(fù)雜度為O(1)。舉例如下:空間復(fù)雜度為O(n) = O(1)。

   let a = 1;
   let b = 2;
   let c = 3;
   console.log('輸出a,b,c', a, b, c);

遞歸實(shí)現(xiàn),調(diào)用fun函數(shù),每次都創(chuàng)建1個(gè)變量k。調(diào)用n次,空間復(fù)雜度O(n*1) = O(n)。

    function fun(n) {
       let k = 10;
       if (n == k) {
           return n;
       } else {
           return fun(++n)
       }
    }

不考慮性能實(shí)現(xiàn),遞歸遍歷查找

主要思路是提供一個(gè)遞getChildren的方法,該方法遞歸去查找子集。 就這樣,不用考慮性能,無(wú)腦去查,大多數(shù)人只知道遞歸,就是寫不出來(lái)。。。

/**
 * 遞歸查找,獲取children
 */
const getChildren = (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);
    }
  }
}
/**
* 轉(zhuǎn)換方法
*/
const arrayToTree = (data, pid) => {
  const result = [];
  getChildren(data, result, pid)
  return result;
}

從上面的代碼我們分析,該實(shí)現(xiàn)的時(shí)間復(fù)雜度為O(2^n)。

不用遞歸,也能搞定

主要思路是先把數(shù)據(jù)轉(zhuǎn)成Map去存儲(chǔ),之后遍歷的同時(shí)借助對(duì)象的引用,直接從Map找對(duì)應(yīng)的數(shù)據(jù)做存儲(chǔ)

function arrayToTree(items) {
  const result = [];   // 存放結(jié)果集
  const itemMap = {};  // 
  // 先轉(zhuǎn)成map存儲(chǔ)
  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;
}

從上面的代碼我們分析,有兩次循環(huán),該實(shí)現(xiàn)的時(shí)間復(fù)雜度為O(2n),需要一個(gè)Map把數(shù)據(jù)存儲(chǔ)起來(lái),空間復(fù)雜度O(n)

最優(yōu)性能

主要思路也是先把數(shù)據(jù)轉(zhuǎn)成Map去存儲(chǔ),之后遍歷的同時(shí)借助對(duì)象的引用,直接從Map找對(duì)應(yīng)的數(shù)據(jù)做存儲(chǔ)。不同點(diǎn)在遍歷的時(shí)候即做Map存儲(chǔ),有找對(duì)應(yīng)關(guān)系。性能會(huì)更好。

function arrayToTree(items) {
  const result = [];   // 存放結(jié)果集
  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;
}

從上面的代碼我們分析,一次循環(huán)就搞定了,該實(shí)現(xiàn)的時(shí)間復(fù)雜度為O(n),需要一個(gè)Map把數(shù)據(jù)存儲(chǔ)起來(lái),空間復(fù)雜度O(n)

小試牛刀

方法1000(條)10000(條)20000(條)50000(條)
遞歸實(shí)現(xiàn)154.596ms1.678s7.152s75.412s
不用遞歸,兩次遍歷0.793ms16.499ms45.581ms97.373ms
不用遞歸,一次遍歷0.639ms6.397ms25.436ms44.719ms

從我們的測(cè)試結(jié)果來(lái)看,隨著數(shù)量的增大,遞歸的實(shí)現(xiàn)會(huì)越來(lái)越慢,基本成指數(shù)的增長(zhǎng)方式。

以上就是高級(jí)前端面試手寫扁平數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)Tree的詳細(xì)內(nèi)容,更多關(guān)于扁平數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)Tree的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊

    ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊

    這篇文章主要為大家介紹了ThreeJS使用紋理貼圖創(chuàng)建一個(gè)我的世界草地方塊的實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解

    TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解

    這篇文章主要為大家介紹了TypeScript實(shí)現(xiàn)十大排序算法之冒泡排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • typescript快速上手的基礎(chǔ)知識(shí)篇

    typescript快速上手的基礎(chǔ)知識(shí)篇

    靜態(tài)類型的typescript與傳統(tǒng)動(dòng)態(tài)弱類型語(yǔ)言javascript不同,在執(zhí)行前會(huì)先編譯成javascript,因?yàn)樗鼜?qiáng)大的type類型系統(tǒng)加持,能讓我們?cè)诰帉懘a時(shí)增加更多嚴(yán)謹(jǐn)?shù)南拗?。注意,它并不是一門全新的語(yǔ)言,所以并沒(méi)有增加額外的學(xué)習(xí)成本
    2022-12-12
  • TypeScript Module Resolution解析過(guò)程

    TypeScript Module Resolution解析過(guò)程

    這篇文章主要為大家介紹了TypeScript Module Resolution解析過(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Three.js?粗糙度貼圖與金屬度貼圖使用介紹

    Three.js?粗糙度貼圖與金屬度貼圖使用介紹

    這篇文章主要為大家介紹了Three.js?粗糙度貼圖與金屬度貼圖使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • TypeScript條件類型示例全面講解

    TypeScript條件類型示例全面講解

    這篇文章主要為大家介紹了TypeScript條件類型示例的全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 與ChatGPT結(jié)對(duì)編程實(shí)現(xiàn)代碼詳解

    與ChatGPT結(jié)對(duì)編程實(shí)現(xiàn)代碼詳解

    這篇文章主要為大家介紹了與ChatGPT結(jié)對(duì)編寫實(shí)現(xiàn)代碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • type challenge刷題之(middle 部分)示例解析

    type challenge刷題之(middle 部分)示例解析

    這篇文章主要為大家介紹了type challenge刷題之(middle 部分)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • TypeScript中的函數(shù)重載示例分析

    TypeScript中的函數(shù)重載示例分析

    這篇文章主要為大家介紹了TypeScript中的函數(shù)重載示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • TypeScript與JavaScript的區(qū)別分析

    TypeScript與JavaScript的區(qū)別分析

    TypeScript可以使用JavaScript中的所有代碼和編程概念,TypeScript是為了使JavaScript的開發(fā)變得更加容易而創(chuàng)建的。推薦先精通JS的的前提下再學(xué)習(xí)TS,這樣更有利于同時(shí)學(xué)習(xí)兩門語(yǔ)言。
    2022-12-12

最新評(píng)論

莒南县| 榆社县| 昌江| 同仁县| 石景山区| 宜宾县| 延安市| 梓潼县| 合水县| 鄂托克前旗| 遂溪县| 内黄县| 苏尼特左旗| 开封市| 锡林郭勒盟| 呼玛县| 石河子市| 嘉善县| 繁昌县| 安徽省| 克山县| 宣武区| 景宁| 海晏县| 眉山市| 海伦市| 吉木萨尔县| 思茅市| 滦平县| 信宜市| 宾川县| 彭泽县| 抚顺县| 芒康县| 唐山市| 濮阳县| 阳曲县| 新沂市| 华阴市| 佛教| 景泰县|