返回
用JavaScript征服Leetcode 144:二叉树的前序扫掠
前端
2023-11-06 23:56:46
作为JavaScript爱好者,我们着迷于探索算法的优雅。Leetcode上的第144题-二叉树的前序扫掠是一道广受欢迎的问题,让我们携手探索它的解决方案,用JavaScript的魔法赋予其生命。
前序扫掠:理解基础
在二叉树中,前序扫掠是一种特殊的树搜索技术,其访问次序为:根节点、左子树、右子树。它在树结构的表示和数据处理中有着重要的应用,因此对于计算机科学家和程序员来说,掌握前序扫掠至关重要。
方法一:基于堆栈的优雅实现
为了使用JavaScript征服第144题,我们的第一个方法是借助栈的数据结构。栈是一种“先进先出”的数据结构,为我们的前序扫掠提供了一个天然的框架。算法的步骤如下:
- 将根节点推入栈中。
- 只要栈不为空,执行以下步骤:
- 弹出栈顶元素并访问它。
- 如果该节点有左子树,将左子树推入栈中。
- 如果该节点有右子树,将右子树推入栈中。
方法二:非基于堆栈的高效实现
虽然基于堆栈的实现简洁优雅,但它在某些情况下可能会导致栈内存溢出。因此,我们探索一种非基于堆栈的实现,它效率更高,并且在处理大树时能够更好地控制内存使用。
- 当前节点指向根节点。
- 如果当前节点不为空,则访问它。
- 如果当前节点有左子树,则让当前节点指向左子树。
- 否则,如果当前节点有右子树,则让当前节点指向右子树。
- 否则,让当前节点指向当前节点的父节点。
- 重复步骤2-5,直到当前节点为null。
时间和空间复杂度
这两种方法的时间复杂度都是O(n),其中n是二叉树中的节点数。这是因为我们访问了每个节点一次且只访问一次。
空间复杂度方面,基于堆栈的实现为O(n),因为在最坏情况下,它将整个树存储在栈中。然而,非基于堆栈的实现只使用常数空间,因为它只存储少量指针。
用JavaScript征服Leetcode
在JavaScript中实现这两个算法非常简单。以下是一个基于堆栈的实现示例:
const preorderTraversal = (root) => {
const stack = [];
const result = [];
if (root) {
stack.push(root);
}
while (stack.length) {
const node = stack.pop();
result.push(node.val);
if (node.left) {
stack.push(node.left);
}
if (node.right) {
stack.push(node.right);
}
}
return result;
};
以下是非基于堆栈的实现示例:
const preorderTraversal = (root) => {
const result = [];
let current = root;
while (current) {
result.push(current.val);
if (current.left) {
current = current.left;
} else if (current.right) {
current = current.right;
} else {
while (current.parent && !current.parent.left) {
current = current.parent;
}
if (current.parent) {
current = current.parent.right;
} else {
current = null;
}
}
}
return result;
};
总结
通过深入了解前序扫掠的算法,并用JavaScript优雅地实现了基于堆栈和非基于堆栈的解决方案,我们征服了Leetcode的第144题。现在,我们不仅掌握了算法本身,而且还理解了其背后的细微差别,从而为我们解决更复杂的算法问题做好了准备。