7字节-抖音团购-全部
> Last Format Time:6/12/2026 21:03:57
一面
提问
主要是围绕着项目来进行的提问,有一些基础的问题。
- 5个视频是怎么减少重排的:这里没有做优化,就是直接卸载了,每次卸载完再重新装载
- 视频是怎么进行管理的:使用队列
- localStorage的大小是多少:5-10MB
代码
将上面的source转化为下面的形式
我自己的实现方式是先遍历一次,将根节点插入到res数组中,然后将这些插入的项移除,然后遍历剩余的部分,将其中pid===id的项添加到父项的children数组中,之后,重复移除,添加的过程,直到res的长度为零(但这其实是我之后想到的,根本不是我面试的想到的,有很多细小的错误,导致我整体的答题效果不是很好,尤其是我一开始的递归思路,source最开始是Array,其Item是对象,自然就不能使用forEach,我没有察觉到这一点。。。)
> ⚠️ 纠错:「source最开始是Array,其Item是对象,自然就不能使用forEach」—— 这个说法有误。Array.prototype.forEach 可以遍历数组中的对象,forEach 是数组方法,数组中存放对象是完全可以使用 forEach 遍历的。这里可能是混淆了其他概念。
上面的思路也是不对的,仔细想想,第一次将根结点取出来了,第二次将一层的节点取出来了,第二层的结点你该如何加入到第一层的节点中呢,所以还是要使用map
// 实现函数将source转换为result
const source = [
{ id: 0, name: "a" },
{ id: 1, name: "b", pid: 0 },
{ id: 2, name: "c", pid: 0 },
{ id: 3, name: "d", pid: 1 },
{ id: 4, name: "e", pid: 2 },
{ id: 5, name: "f" },
{ id: 6, name: "g", pid: 3 },
{ id: 7, name: "h", pid: 5 },
{ id: 8, name: "i", pid: 7 },
];
const result = [
{
id: 0,
name: "a",
children: [
{
id: 1,
name: "b",
pid: 0,
children: [
{
id: 3,
name: "d",
pid: 1,
children: [{ id: 6, name: "g", pid: 3 }],
},
],
},
{ id: 2, name: "c", pid: 0, children: [{ id: 4, name: "e", pid: 2 }] },
],
},
{
id: 5,
name: "f",
children: [
{ id: 7, name: "h", pid: 5, children: [{ id: 8, name: "i", pid: 7 }] },
],
},
];
答案:
法一:
function arrayToTree(source) {
const tree = []; // 存放最终的树形结构,存放树的根结点,就是没有pid的结点
const map = {}; // 哈希表,用于存储 id 到节点的映射
// 1. 第一次遍历:将所有节点存入 map,并初始化 children 数组
source.forEach(item => {
map[item.id] = { ...item, children: [] };
});
// 2. 第二次遍历:建立父子关系
source.forEach(item => {
const node = map[item.id]; // 当前节点
// 如果存在 pid,说明它不是根节点
if (item.pid !== undefined && map[item.pid]) {
// 找到父节点,将当前节点 push 进父节点的 children
map[item.pid].children.push(node);
} else {
// 如果不存在 pid 或找不到父节点,说明它是根节点
tree.push(node);
}
});
return tree;
}
// 测试数据
const source = [
{ id: 0, name: "a" },
{ id: 1, name: "b", pid: 0 },
{ id: 2, name: "c", pid: 0 },
{ id: 3, name: "d", pid: 1 },
{ id: 4, name: "e", pid: 2 },
{ id: 5, name: "f" },
{ id: 6, name: "g", pid: 3 },
{ id: 7, name: "h", pid: 5 },
{ id: 8, name: "i", pid: 7 },
];
const result = arrayToTree(source);
console.log(JSON.stringify(result, null, 2));
法一的Map实现:
const fn = (source) => {
let root = []
let map = new Map()
// 遍历source,将每个item添加到map中
source.forEach((item) => {
// map.set(item.pid, item) 这里将对象展开,添加了一个children属性
map.set(item.id, { ...item, children: [] })
})
console.log('map: ', map)
map.forEach((item) => {
console.log(item)
})
map.forEach((item) => {
if (item.pid === undefined) {
// 如果是根节点,直接添加到root中
root.push(map.get(item.id))
} else {
// 如果不是根节点,将当前item添加到父节点的children中
console.log(item.pid)
map.get(item.pid).children.push(map.get(item.id))
}
})
console.log('root: ', root)
return root
}
fn(source)
// root: [
// { id: 0, name: 'a', children: [[Object], [Object]] },
// { id: 5, name: 'f', children: Object },
// ]
法二:
function arrayToTreeRecursive(source, pid = undefined) {
const tree = [];
// 筛选出所有父级 ID 等于当前 pid 的节点
source.forEach(item => {
if (item.pid === pid) {
// 找到子节点后,递归查找该子节点的子节点
const children = arrayToTreeRecursive(source, item.id);
if (children.length > 0) {
tree.push({ ...item, children });
} else {
tree.push({ ...item });
}
}
});
return tree;
}
// 调用方式:默认从 pid 为 undefined 或 null 的根节点开始找
// 注意:你的数据中根节点没有 pid 字段,所以默认传 undefined 即可匹配
const result = arrayToTreeRecursive(source);
console.log(JSON.stringify(result, null, 2));
加分项:
// 在解法一返回前,增加这一步清洗(可选)
function cleanEmptyChildren(node) {
if (node.children && node.children.length === 0) {
delete node.children; // 删除空的 children 数组
} else if (node.children) {
node.children.forEach(cleanEmptyChildren); // 递归清洗子节点
}
}
// 使用示例:
// result.forEach(cleanEmptyChildren);
二面
- 时间:4/22/26(周三)
提问
全部是围绕着项目来的
代码
- Promise.All() > ⚠️ 纠错:正确写法为
Promise.all()(首字母小写) - 大数相加(转为字符串)
两道题都没有写出来,都是写了大体的结构,具体的细节不记得了,反正是刚背完就忘了。。。
三面
提问
- 围绕着上一段的实习经历来的,我的回答重点在于skill的构建,至于说我的挑战是什么,我也不到。。。
代码
- 没有写,只需要你复述出来就行
- 寻找两个链表中的第一个重复的节点
- 图片的压缩算法、如果你是计算机系统的开发者,你该如何将图片存入外存,你准备使用什么数据结构来存呢
复盘
这三个面试整体上,与之前的日常实习相比来讲,更加的实用主义,直接就是考察代码与项目。现在是周日(26号),算上今天,我已经休息了4天了,啥也没干,就是玩游戏哈哈哈,该复出了。
面试没过,但是被其他部门捞走了,AI全栈开发,我也不会啊,宝子们。。。
一开始的时候我就觉得为什么这次面的这么快,30多分钟就结束了,没想到是被刷了。。。