是面试的时候问到的题目,没有用很多case去测,不保证代码完全正确
题目
节点结构:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) {
val = x;
}
}
完全二叉树:
叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部
给出完全二叉树,返回底层最右节点的值
解法一:遍历
时间复杂度:n
不管深搜还是广搜,在最差的情况下,都需要遍历所有节点,即时间复杂度为n
深搜
public class DeepestTraverse {
// 记录当前碰到最下边的层的最右节点的值
private Integer result;
// result所在的层
private int resultLevel;
public int getMostRightBottomNode(TreeNode root) {
deepestTraverse(root, 0);
return result;
}
public void deepestTraverse(TreeNode node, int level) {
if (node.left == null && node.right == null) {
if (result == null) {
// 如果是叶子节点并且result还没有初始化,则对result和resultLevel赋值(实际就是初始化根节点的值)
result = node.val;
resultLevel = level;
} else if (level > resultLevel) {
// 如果是叶子节点,并且result已被初始化的情况下,如果当前节点的层级比resultLevel高,则赋值给result和resultlevel(因为每次是先走右节点,因此保证一个层级中,只会记录最右节点)
result = node.val;
resultLevel = level;
}
} else {
// 每次先走有节点,再走左节点
if (node.right != null) {
deepestTraverse(node.right, level + 1);
}
if (node.left != null) {
deepestTraverse(node.left, level + 1);
}
}
}
}
广搜
public class BreadthTraverse {
public int getMostRightBottomNode(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
// 记录当前层的满节点的数量
int levelSize = 1;
// cursor在当前层走了几个节点
int cursorIndex = 0;
// 用于遍历的节点
TreeNode cursor = null;
do {
cursor = queue.poll();
cursorIndex++;
// 当cursorIndex等于levelSize,代表当前层已经走完,对cursorIndex和levelSize进行设置
if (cursorIndex == levelSize) {
cursorIndex = 0;
levelSize *= 2;
}
// 每次先加左节点,再加右节点,因此cursor保持为遍历过的节点中的最底层的最右节点
if (cursor.left != null) {
queue.add(cursor.left);
}
if (cursor.right != null) {
queue.add(cursor.right);
}
} while (!queue.isEmpty());
return cursor.val;
}
}
解法二:二分
面试现场,在面试官的努力提醒下,还是没完整的捋出来。。。后面回来捋了捋,即使逻辑上捋顺路, 代码写起来也很复杂啊。。
时间复杂度:logn
- 找出最大层数(根据完全二叉树特性,只需要往最左边走即可)
- 二分遍历二叉树,简单来说就是把底层所有节点(包含空节点)看成一个数组,对这个数组通过二分的方法进行遍历
以一个4层的二叉树为例:
以上图为例的步骤:
- 检查 底层-下标4 的值((0+8)/2),判断为空,因此目标应该在左边
- 检查 底层-下标1 的值((0+3)/2),判断有值,因此目标可能出现在右边或者就