问题
给定一个二叉树,在树的最后一行找到最左边的值
示例 1:
输入:
2<br /> / \<br /> 1 3<br />输出:1<br /> <br />示例 2:<br />输入:<br /> 1<br /> / \<br /> 2 3<br /> / / \<br /> 4 5 6<br /> /<br /> 7<br />输出:7
解法一:递归
这道题目用递归的话就就一直向左遍历,最后一个就是答案么?
肯定不是,一直向左遍历到最后一个,它未必是最后一行
我们来分析一下题目:在树的最后一行找到最左边的值
首先要是最后一行,然后是最左边的值
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行
所以要找深度最大的叶子节点
那么如何找最左边的呢?可以使用前序遍历,这样才先优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值
递归三部曲:
- 确定递归函数的参数和返回值
- 参数必须有要遍历的树的根节点,还有就是一个
int
型的变量用来记录最长深度。这里就不需要返回值了,所以递归函数的返回类型为void
- 参数必须有要遍历的树的根节点,还有就是一个
本题还需要类里的两个全局变量,maxLen用来记录最大深度,maxleftValue记录最大深度最左节点的数值
int maxLen = INT_MIN; // 全局变量 记录最大深度
int maxleftValue; // 全局变量 最大深度最左节点的数值
void traversal(TreeNode root, int leftLen)
那么递归函数的返回值为啥不能返回最长深度呢?
递归函数什么时候要有返回值,什么时候不能有返回值?
如果需要遍历整颗树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!
本题我们是要遍历整个树找到最深的叶子节点,需要遍历整颗树,所以递归函数没有返回值
确定终止条件
- 当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度
if (root.left == null && root.right == null) { if (leftLen > maxLen) { maxLen = leftLen; // 更新最大深度 maxleftValue = root.val; // 最大深度最左面的数值 } return; }
- 当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度
确定单层递归的逻辑
- 在找最大深度的时候,递归的过程中依然要使用回溯
// 中 if (root.left) { // 左 leftLen++; // 深度加一 traversal(root.left, leftLen); leftLen--; // 回溯,深度减一 } if (root.right) { // 右 leftLen++; // 深度加一 traversal(root.right, leftLen); leftLen--; // 回溯,深度减一 } return;
class Solution { int maxLen = -1; int maxleftValue; void traversal(TreeNode root, int leftLen) { if (root.left == null && root.right == null) { if (leftLen > maxLen) { maxLen = leftLen; maxleftValue = root.val; } return; } if (root.left != null) { leftLen++; traversal(root.left, leftLen); leftLen--; // 回溯 } if (root.right != null) { leftLen++; traversal(root.right, leftLen); leftLen--; // 回溯 } return; } int findBottomLeftValue(TreeNode root) { traversal(root, 0); return maxleftValue; } }
//简化 class Solution { int maxLen = -1; int maxleftValue; void traversal(TreeNode root, int leftLen) { if (root.left == null && root.right == null) { if (leftLen > maxLen) { maxLen = leftLen; maxleftValue = root.val; } return; } if (root.left != null) { traversal(root.left, leftLen + 1); // 隐藏着回溯 } if (root.right != null) { traversal(root.right, leftLen + 1); // 隐藏着回溯 } return; } int findBottomLeftValue(TreeNode root) { traversal(root, 0); return maxleftValue; } };
- 在找最大深度的时候,递归的过程中依然要使用回溯
解法二:迭代法
class Solution {
int findBottomLeftValue(TreeNode root) {
int result = 0;
if(root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (i == 0) {
result = node.val;
} // 记录最后一行第一个元素
if (node.left != null)
queue.offer(node.left);
if (node.right != null)
queue.offer(node.right);
}
}
return result;
}
}