前端手写题之 树 场景题 js

本人github链接 求follow

前端手写题集锦 use js 记录大厂面试常考手写题,github仓库地址:https://github.com/Sunny-117/Front-end-handwritten-question。伴随秋招陆续更新,求star

前端手写题系列文章: 前端手写题之正则表达式 前端手写题之 树 场景题 js 前端手写题之JavaScript 原生方法重写

鉴于现在的手写题还有笔试题都常考树形结构,本人面试笔试也遇到很多,所以总结了以下几个题,几乎覆盖所有笔面试场景,希望对uu们有用

如果认为题解有问题或者不是最优解,欢迎提issue

DOM2JSON

{
  tag: 'DIV',
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}

function dom2Json(domtree) {
  let obj = {};
  obj.name = domtree.tagName;
  obj.children = [];
  domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child)));
  return obj;
}

将虚拟 Dom 转化为真实 Dom

{
  tag: 'DIV',
  attrs:{
  id:'app'
  },
  children: [
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] }
      ]
    },
    {
      tag: 'SPAN',
      children: [
        { tag: 'A', children: [] },
        { tag: 'A', children: [] }
      ]
    }
  ]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
  <span>
    <a></a>
  </span>
  <span>
    <a></a>
    <a></a>
  </span>
</div>
// 真正的渲染函数
function _render(vnode) {
  // 如果是数字类型转化为字符串
  if (typeof vnode === "number") {
    vnode = String(vnode);
  }
  // 字符串类型直接就是文本节点
  if (typeof vnode === "string") {
    return document.createTextNode(vnode);
  }
  // 普通DOM
  const dom = document.createElement(vnode.tag);
  if (vnode.attrs) {
    // 遍历属性
    Object.keys(vnode.attrs).forEach((key) => {
      const value = vnode.attrs[key];
      dom.setAttribute(key, value);
    });
  }
  // 子数组进行递归操作
  vnode.children.forEach((child) => dom.appendChild(_render(child)));
  return dom;
}

计算目录树的深度

const tree = {
    name: 'root',
    children: [
        { name: '叶子1-1' },
        { name: '叶子1-2' },
        {
            name: '叶子2-1',
            children: [{
                name: '叶子3-1',
                children: [{
                    name: '叶子4-1',
                    children: [{}]
                }]
            }]
        }
    ]
}

function getLevel(tree) {
    if (tree == null) return 0;
    const queue = [tree]
    let dep = 0;
    while (queue.length) {
        dep++;
        const size = queue.length
        for (let i = 0; i < size; i++) {
            const node = queue.shift()
            if (node.children) {
                for (const child of node.children) {
                    queue.push(child)
                }
            }
        }
    }
    return dep
}
console.log(getLevel(tree));

树形结构获取路径名

const treeData = [
    {
        name: "root",
        children: [
            { name: "src", children: [{ name: "index.html" }] },
            { name: "public", children: [] },
        ],
    },
];
const RecursiveTree = (data) => {
    const res = []
    const dfs = (data) => {
        data.forEach(ele => {
            res.push(ele.name)
            ele.children && dfs(ele.children)
        });
    }
    dfs(data)
    return res;
}
console.log(RecursiveTree(treeData));

树形结构转成列表

const data = [
    {
        id: 1,
        text: '节点1',
        parentId: 0,
        children: [
            {
                id: 2,
                text: '节点1_1',
                parentId: 1
            }
        ]
    }
]
//直接放,删除逻辑
function treeToList(data) {
    let res = [];
    const dfs = (tree) => {
        tree.forEach((item) => {
            if (item.children) {
                dfs(item.children);
                delete item.children;
            }
            res.push(item);
        });
    };
    dfs(data);
    return res;
}
//直接放需要的,我写的
function treeToList(data) {
    const res = []
    function dfs(data) {
        const obj = {}
        data.forEach(ele => {
            obj.id = ele.id
            obj.text = ele.text
            obj.parentId = ele.parentId
            ele.children && dfs(ele.children)
        });

        res.push(obj)
    }
    dfs(data)
    return res;
}

console.log(treeToList(data));

列表转成树形结构

const rootList = [
    { id: 1, parent: null, text: "菜单1" },
    { id: 11, parent: 1, text: "菜单1-1" },
    { id: 12, parent: 1, text: "菜单1-2" },
    { id: 2, parent: null, text: "菜单2" },
    { id: 21, parent: 2, text: "菜单2-1" },
];

function getTreeList(rootList, id, list) {
    for (const item of rootList) {
        if (item.parent === id) {
            list.push(item);
        }
    }
    for (const i of list) {
        i.children = [];
        getTreeList(rootList, i.id, i.children);
        if (i.children.length === 0) {
            delete i.children;
        }
    }
    return list;
}
const res = getTreeList(rootList, null, []);
console.log("res", res);

对象树遍历

const tree = {
    name: 'root',
    children: [
        {
            name: 'c1',
            children: [
                {
                    name: 'c11',
                    children: []
                },
                {
                    name: 'c12',
                    children: []
                }
            ]
        },
        {
            name: 'c2',
            children: [
                {
                    name: 'c21',
                    children: []
                },
                {
                    name: 'c22',
                    children: []
                }
            ]
        }
    ]
}

// 深度优先的方式遍历 打印 name
// ['root', 'c1','c11', 'c12', 'c2', 'c21', 'c22']
// 我写的
function solve(root) {
    const res = []
    function dfs(root) {
        for (const key in root) {
            if (key === 'name') {
                res.push(root[key])
            } else if (key === 'children') {
                root[key].forEach(ele => {
                    dfs(ele)
                });
            }
        }
    }
    dfs(root)
    return res;
}
console.log(solve(tree));

获取树对象属性

var tree = {
    name: '中国',
    children: [
        {
            name: '北京',
            children: [
                {
                    name: '朝阳群众'
                },
                {
                    name: '海淀区'
                },
                {
                    name: '昌平区'
                }
            ]
        },
        {
            name: '浙江省',
            children: [
                {
                    name: '杭州市',
                    code: '0571',
                },
                {
                    name: '嘉兴市'
                },
                {
                    name: '绍兴市'
                },
                {
                    name: '宁波市'
                }
            ]
        }
    ]
};

function fn(tree, name) {
    const obj = {}
    function dfs(tree) {
        for (const key in tree) {
            if (tree.name === name) {
                obj[key] = tree[key]
            } else {
                tree.children && tree.children.forEach(ele => {
                    dfs(ele)
                });
            }
        }
    }
    dfs(tree)
    return obj
}

function fn(tree, name) {
    //bfs
    let Queue = [[tree.name, tree.children]];
    while (Queue.length > 0) {
        //出队当前节点
        let cur = Queue.shift();
        if (cur[0] === name) return { name: name, code: cur[1] }
        //将children入队
        if (cur.length === 1) continue;

        for (let node of cur[1]) {
            let obj = [node.name];
            if (node.hasOwnProperty("children")) obj.push(node.children);
            if (node.hasOwnProperty("code")) obj.push(node.code);
            Queue.push(obj);
        }
    }
    return -1;
}
var node = fn(tree, '杭州市');
console.log(node);    // { name: '杭州市', code: 0571 }

查找json中的children路径 现有如下json(简化为对象),已知每个节点id唯一,编写findNode(id),返回路径,如findNode(5 输出 1->4->5

json = {
    id: 1,
    children: [
        { id: 2, children: [{ id: 3, children: [] }] },
        {
            id: 4,
            children: [
                { id: 5, children: [] },
                { id: 6, children: [] },
            ],
        },
        { id: 7, children: [] },
    ],
};
let result = []
// 独立完成
function findNode(obj) {
    const res = []
    function dfs(obj, currPath, target) {
        if (!obj) return;
        if (obj.id === target) {
            currPath += obj.id
            res.push(currPath)
            return
        }
        currPath += obj.id + '->'
        obj.children && obj.children.forEach(ele => {
            dfs(ele, currPath, target)
        });
    }
    dfs(obj, '', 5)
    return res;
}
console.log(findNode(json));

对象字符串转化成树形结构

let strarr = {  
  'a-b-c-d':1,  
  'a-b-c-e':2,  
  'a-b-f':3,  
  'a-j':4  
}  
let obj = {  
  a:{  
    b:{  
      c:{  
        d:1,  
        e:2  
      },  
      f:3  
    },  
    j:4  
  }  
} 
function parse(obj) {
  let ans = {}
  for (let att in obj) {
    let temp = ans;
    for (let i = 0, len = att.length; i < len; i += 2) {
      let cur = att[i];
      if (i == len - 1) {
        temp[cur] = obj[att];
      } else {
        if (!temp[cur]) {
          temp[cur] = {};
        }
        temp = temp[cur];
      }
    }
  }
  return ans;
}

判断有无符合路径和 -> 打印所有路径

const data3 = [
    {
        id: 1,
        name: '前端',
        children: [
            {
                id: 2,
                name: 'html',
                children: [
                    { id: 5, name: 'vue', children: [] },
                    { id: 6, name: 're', children: [] },
                ]
            },
            {
                id: 3,
                name: 'html',
                children: [
                    { id: 7, name: 'vue', children: [] },
                    { id: 8, name: 're', children: [] },
                ]
            }
        ]
    }
]
function findData(data, id = 1) {
    let queue = [data[0]]
    let map = new Map()
    map.set(data[0], [data[0].name])
    while (queue.length) {
        let length = queue.length
        for (let i = 0; i < length; i++) {
            let node = queue.shift()
            for (let i = 0; i < node.children.length; i++) {
                if (node.children[i].id === id) {
                    return [...map.get(node), node.children[i].name].join('-')
                } else {
                    queue.push(node.children[i])
                    map.set(node.children[i], [...map.get(node), node.children[i].name])
                }
            }
        }
        console.log(map);
    }

}
console.log(findData(data3, 5));//前端-html-vue

#算法##前端工程师##秋招##如何反向拿捏领导##后端开发实习生#
全部评论
强哥🥹
点赞
送花
回复
分享
发布于 2022-09-14 10:23 湖南
强哥
点赞
送花
回复
分享
发布于 2022-09-15 00:48 江苏
滴滴
校招火热招聘中
官网直投
好文
点赞
送花
回复
分享
发布于 2022-09-15 06:57 湖北
太强了
点赞
送花
回复
分享
发布于 2022-10-27 10:03 湖北

相关推荐

28 120 评论
分享
牛客网
牛客企业服务