前言
无论你是 Java,Python,还是 PHP,面试总逃脱不了一个问题:算法!
据统计,各大厂笔试平均通过率只有 10%~20%,基本都折在了算法上。
很多同学都问过这个问题,毕竟,在实际工作中,我们几乎根本不可能从底层实现一遍经典算法。如果真的以工作内容为导向,算法还真可能对绝大部分同学来说没什么用。
但是,算法却是大厂面试考察的重点。甚至,极端一些,国外一些大厂只考算法。
为什么会这样?在这篇文章中,我打算系统阐述一下这个问题。相信会对你有启发。
递归方法
递归是解决树形结构问题的一种常用方法。对于扁平数据结构,我们可以通过递归的方式构建出一棵树。具体来说,我们可以从根节点开始,逐个遍历所有节点。对于每个节点,我们可以通过它的父节点ID来找到它的父节点,然后将其添加到父节点的子节点中。这样我们就可以递归地构建出一棵完整的树形结构。
function flatToTree(flatArr, rootId) {
const tree = {};
flatArr.forEach(node => {
if (node.id === rootId) {
tree[node.id] = node;
} else {
if (!tree[node.parentId].children) {
tree[node.parentId].children = {};
}
tree[node.parentId].children[node.id] = node;
}
});
return tree[rootId];
}
优点是代码简洁易懂,适合处理小规模数据。缺点是对于大规模数据的处理会导致栈溢出,性能较差
栈方法
除了递归,我们还可以使用栈来解决这个问题。我们可以先将根节点入栈,然后逐个遍历所有节点。对于每个节点,我们可以通过它的深度来判断它应该添加到哪个节点下面。具体来说,我们可以将栈中深度小于当前节点深度的节点全部弹出,然后将当前节点添加到栈顶节点的子节点中。这样我们就可以使用栈来构建出一棵完整的树形结构。
function flatToTree(flatArr, rootId) {
const stack = [];
const map = {};
const tree = {};
flatArr.forEach(node => {
map[node.id] = node;
});
tree[rootId] = map[rootId];
stack.push(tree[rootId]);
while (stack.length) {
const currentNode = stack.pop();
const parentId = currentNode.id;
flatArr.forEach(node => {
if (node.parentId === parentId) {
if (!currentNode.children) {
currentNode.children = {};
}
currentNode.children[node.id] = node;
stack.push(currentNode.children[node.id]);
}
});
}
return tree[rootId];
}
优点是性能较好,适合处理大规模数据。迭代算法的缺点是代码较为复杂,需要额外维护栈结构
哈希表
除了上述两种方法,我们还可以使用哈希表来解决这个问题。我们可以先将所有节点添加到哈希表中,以节点ID为键,节点对象为值。然后我们可以逐个遍历所有节点,对于每个节点,我们可以通过它的父节点ID在哈希表中查找对应的父节点,然后将其添加到父节点的子节点中。这样我们就可以使用哈希表来构建出一棵完整的树形结构。
function flatToTree(flatArr, rootId) {
const map = {};
flatArr.forEach(node => {
map[node.id] = node;
});
const tree = {};
flatArr.forEach(node => {
if (node.id === rootId) {
tree[node.id] = node;
} else {
const parent = map[node.parentId];
if (!parent.children) {
parent.children = {};
}
parent.children[node.id] = node;
}
});
return tree[rootId];
}
Map算法的优点是性能较好,代码简洁易懂,适合处理大规模数据。缺点是需要额外创建Map对象,空间复杂度较高
总结
扁平数据结构转Tree是一个常见的算法问题,解决这个问题有多种方法。本文从递归、栈和哈希表三个角度探讨了如何解决这个问题,可以看出三种实现扁平数据结构转换为树形结构的算法各有优缺点。递归算法简单易懂但性能较差,迭代算法性能较好但代码较为复杂,Map算法性能较好但空间复杂度较高。综合来看,Map算法是性能最好的写法。
工作中掌握了数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。因为这样的你,就像是站在巨人的肩膀上,拿着生存利器行走世界。