思路
递归方法:
深度优先搜索
- 先访问根结点
- 根结点存在子节点
- 访问左节点
- 访问右节点
非递归方法:
以显示栈的方式模仿递归。
- 初始化栈,并将根节点入栈;
- 当栈不为空时:
- 弹出栈顶元素 n,并将值添加到结果中
- 如果 n 的右节点存在,入栈
- 如果 n 的左节点存在,入栈
- 输出结果数组
题解
方法一(非递归)
var preorderTraversal = function(root) {
const stack = []
const res = []
// 1.若存在根结点,入栈(出栈)
if (root) {stack.push(root)}
// 3.若根结点有 左节点 或 右节点,循环
while (stack.length) {
// 1.1 根结点出栈,值添加到结果数组中存放
const n = stack.pop()
res.push(n.val)
// 2.若存在右节点,左节点,入栈。推出栈顶,即,作为 根结点 出栈
if(n.right) stack.push(n.right)
if(n.left) stack.push(n.left)
}
return res
};
方法二 (递归)
var preorderTraversal = function(root, r = []) {
if (!root) return []
r.push(root.val)
r = r.concat(preorderTraversal(root.left))
r = r.concat(preorderTraversal(root.right))
return r
};
方法三 (递归)
一行代码。现阶段最优解了
var preorderTraversal = function(root) {
return root ? [root.val,...preorderTraversal(root.left), ...preorderTraversal(root.right)] : []
};
思考与改进
方法一
if (root) {stack.push(root)}
可写作
root && stack.push(root)
if(n.right) stack.push(n.right)
可写作
n.right && stack.push(n.right)
方法三
…是JS中扩展运算符。ES6中新增。
可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时将对象表达式按照key-value的方式展开。
作用约等于脱去括号。不管大括号([])、花括号({})。
...preorderTraversal(root.left)
在此处,可以理解为
[root.val].concat(preorderTraversal(root.left)
后续会再总结一篇关于(…)扩展运算符的文章。