携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第34天,点击查看活动详情 >>
递归法求二叉树最底层最左边的结点值
题目分析
题目的意思是给定一棵二叉树,让我们设置一定的算法来实现求的该二叉树最底层的最左边的结点的值。
并且是要使用递归的方式!
算法分析
题目要求用的是递归的方法,首先我们要明白递归的一个整体过程:使用递归就意味着这是一种深度优先的算法。
在二叉树中的深度优先,那递归就是会从一处直接到达最底层,再依次回溯处理。
也正因为这样,我们需要让递归从最左边到达最底层,也就是递归顺序是先左后右。
确定了我们遇到的结点都首先会是每一层的最左节点之后,这样的话,我们接下来只需要判断当前结点是否是叶子结点,再根据情况做出相应的处理即可。
如果当前结点是叶子结点,则要判断一下当前深度是不是要比曾经记录的深度要大,如果当前深度要比曾经记录的深度要大,则用当前结点的值覆盖曾经的值,用当前深度覆盖曾经深度。
深度的判断主要是确保处理结点是该层首次遇到的结点(即该层最左结点)
具体实现
下面我们来看看这个递归求解的算法过程:
递归终止条件:
if (root.left == null && root.right == null) {
// 如果当前深度大于曾经的记录深度的话,就需要更改曾经记录的值
//并将记录深度改为当前深度
if (left[1] < deep) {
left[1] = deep;
left[0] = root.val;
}
return;
}
递归过程:
/**
* 和二叉树的深度有关,或者说要记录二叉树深度的,一般在递归方法中都需要使用回溯
* 这样才能准确地记录住左右两边的深度
*/
if (null != root.left) {
getLeft(root.left, deep + 1);
}
if (null != root.right) {
getLeft(root.right, deep + 1);
}
经过了以上分析,我们很快就可以实现了整个算法的完整代码,具体实现如下所示:
递归调用函数:
int[] left = new int[]{0, Integer.MIN_VALUE};
public int findBottomLeftValue(TreeNode root) {
getLeft(root, 0);
return left[0];
}
递归函数:
public void getLeft (TreeNode root, int deep) {
if (root.left == null && root.right == null) {
// 如果当前深度大于曾经的记录深度的话,就需要更改曾经记录的值
//并将记录深度改为当前深度
if (left[1] < deep) {
left[1] = deep;
left[0] = root.val;
}
return;
}
/**
* 和二叉树的深度有关,或者说要记录二叉树深度的,一般在递归方法中都需要使用回溯
* 这样才能准确地记录住左右两边的深度
*/
if (null != root.left) {
getLeft(root.left, deep + 1);
}
if (null != root.right) {
getLeft(root.right, deep + 1);
}
return;
}
总结:
本次文章中,我们介绍了如何用递归的方法去求解二叉树的最底层的最左边的结点,下面我们来一起总结一下一些重要的算法思想吧。
在遇到叶子结点时 判断当前叶子结点的深度是不是比上一次记录最左边的值的深度要大; 如果是更大的话,就将当前层的最左边的值覆盖掉曾经记录的值 如果更小的话,就保留曾经值 这里只是判断了当前节点是叶子结点,可是它并没有说明是左边的叶子结点还是右边的叶子结点, 那这里逻辑实现的理由是什么呢?
首先我们要明白一个点,在使用递归方法之前我们就应该知道: 递归应该是先左后右的,也就是说,在最底层的最左边的结点肯定是要最先可达的 注意可达并不代表这一定是前序遍历,其实这里无论是采用前序遍历,中序遍历,又或者是后序遍历都是可以的 对顺序的要求只有一个,那就是先递归左边的,再递归右边的
在先左后右的这种条件下,在遇到叶子结点时只需要判断当前深度是否大于曾经记录深度, 再根据相应的情况处理即可。 这样子每次记录的都是第一次到达该深度的最左边的叶子结点