题目一:
解法一:(递归)
解题思路:首先要是最后一行,然后是最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
所以要找深度最大的叶子节点。
那么如果找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
递归三部曲:
- 确定递归函数的参数
参数必须要有遍历的树的根节点,还需要一个depth变量记录当前的深度。
本题还需要类里的两个全局变量,maxDepth用来记录最大深度,result记录最大深度最左节点的数值。
- 确定终止条件
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
if (cur.left === null && cur.right === null) {
if (depth > maxDepth) {
maxDepth = depth
result = cur.val
}
return
}
- 确定单层递归的逻辑
cur.left && traversal(cur.left, depth + 1)
cur.right && traversal(cur.right, depth + 1)
完整代码如下:
var findBottomLeftValue = function(root) {
let maxDepth = 0
let result = null
var traversal = function(cur, depth) {
if (cur.left === null && cur.right === null) {
if (depth > maxDepth) {
maxDepth = depth
result = cur.val
}
return
}
cur.left && traversal(cur.left, depth + 1)
cur.right && traversal(cur.right, depth + 1)
}
traversal(root, 1)
return result
};
解法二:(迭代)
解题思路:本题使用层序遍历再合适不过了,比递归要好理解的多!
只需要记录最后一行第一个节点的数值就可以了。
var findBottomLeftValue = function(root) {
let queue = [root]
let result = null
while(queue.length) {
let length = queue.length
for(let i = 0; i < length; i++) {
let node = queue.shift()
if (i === 0) {
result = node.val
}
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
return result
};
注意:JS数组中shift为删除数组第一个元素,unshift在数组首部添加一个元素。
广度优先搜索:
使用广度优先搜索遍历每一层的节点。在遍历一个节点时,需要先把它的非空右子节点放入队列,然后再把它的非空左子节点放入队列,这样才能保证从右到左遍历每一层的节点。广度优先搜索所遍历的最后一个节点的值就是最底层最左边节点的值。
var findBottomLeftValue = function(root) {
let ret = 0;
const queue = [root];
while (queue.length) {
const p = queue.shift();
if (p.right) {
queue.push(p.right);
}
if (p.left) {
queue.push(p.left);
}
ret = p.val;
}
return ret;
};