104. 二叉树的最大深度 - 力扣(LeetCode)
明确高度与深度区别:高度是叶子节点到根节点的距离。深度是根节点到叶子节点的距离
1、BSF:计算累计每一层的数量,返回即可
/**
* 104. 二叉树的最大深度---BSF
* 给定一个二叉树,找出其最大深度。
* 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
* 说明: 叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
public int maxDepth(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
int result = 0;
if (root != null) {
queue.add(root);
}
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.remove();
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
result++;
}
return result;
}
2、DSF后序:根据最大高度遍历,才有后序遍历。遇到空节点时返回0,先处理左节点高度,再处理右节点高度,最后处理中间节点去左右节点的最大值,同时+1给自己这一层加。返回结果即可。
/**
* 104. 二叉树的最大深度--DSF
* 给定一个二叉树,找出其最大深度。
* 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
* 说明: 叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftHigh = maxDepth(root.left);
int rightHigh = maxDepth(root.right);
return Math.max(leftHigh, rightHigh) + 1;
}
3、DSF前序:使用回溯,同时使用前序遍历。先处理中间节点,然后处理左右节点,但是返回时左右节点深度需要-1,是因为要返回到当前中间节点。处理到最深的叶子节点时,再返回深度结果。
/**
* 104. 二叉树的最大深度--DSF前序
* 给定一个二叉树,找出其最大深度。
* 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
* 说明: 叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
int result;
public int maxDepth2(TreeNode root) {
result = 0;
if (root == null) {
return 0;
}
getMaxDepth(root, 1);
return result;
}
private void getMaxDepth(TreeNode root, int deep) {
result = Math.max(deep, result);
if (root.left == null && root.right == null) {
return;
}
if (root.left != null) {
deep++;
getMaxDepth(root.left, deep);
deep--;
}
if (root.right != null) {
deep++;
getMaxDepth(root.right, deep);
deep--;
}
return;
}
111. 二叉树的最小深度 - 力扣(LeetCode)
1、BSF:判定每层节点的左右节点是否都为空,如果是空则说明该节点时子节点,再返回累计的层数即可。
/**
* 111. 二叉树的最小深度---BSF
* 给定一个二叉树,找出其最小深度。
* 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
* 说明:叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
public int minDepth(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
int result = 0;
if (root != null) {
queue.add(root);
}
while (!queue.isEmpty()) {
int size = queue.size();
result++;
for (int i = 0; i < size; i++) {
TreeNode node = queue.remove();
if (node.left == null && node.right == null) {
return result;
}
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
return result;
}
2、DSF后序: 也是根据后序遍历最小高度,但需要对空节点做额外判定。如果左节点为空,右节点不为空,则只返回右节点高度,反之返回左节点的。都不为空是则比较那个最小。再把结果返回即可。
/**
* 111. 二叉树的最小深度---DSF
* 给定一个二叉树,找出其最小深度。
* 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
* 说明:叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
public int minDepth1(TreeNode root) {
if (root == null) {
return 0;
}
int leftHigh = minDepth1(root.left);
int rightHigh = minDepth1(root.right);
if (root.left == null && root.right != null) {
return rightHigh + 1;
} else if (root.left != null && root.right == null) {
return leftHigh + 1;
} else {
return Math.min(leftHigh, rightHigh) + 1;
}
}
3、DSF前序回溯。与递归思路类似,但求最小深度时,当遍历到叶子节点时则比较最小深度
/**
* 111. 二叉树的最小深度---DSF前序
* 给定一个二叉树,找出其最小深度。
* 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
* 说明:叶子节点是指没有子节点的节点。
*
* @param root
* @return
*/
int resultMin ;
public int minDepth2(TreeNode root) {
resultMin = Integer.MAX_VALUE;
if (root == null){
return 0;
}
getMinDepth(root,1);
return resultMin;
}
private void getMinDepth(TreeNode root, int deep) {
if (root.left == null && root.right == null){
resultMin = Math.min(deep,resultMin);
return;
}else if (root.left == null && root.right !=null){
deep++;
getMinDepth(root.right,deep);
deep--;
}else if (root.left != null && root.right ==null){
deep++;
getMinDepth(root.left,deep);
deep--;
}else {
deep++;
getMinDepth(root.left,deep);
deep--;
deep++;
getMinDepth(root.right,deep);
deep--;
}
}
222. 完全二叉树的节点个数 - 力扣(LeetCode)
1、BSF:遍历每个节点时累计即可
/**
* 222. 完全二叉树的节点个数
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
if (root != null) {
queue.add(root);
}
int result = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.remove();
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
result++;
}
}
return result;
}
2、DSF后序遍历:遍历每个元素时累计即可,下同
/**
* 222. 完全二叉树的节点个数---DSF后序遍历
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes1(TreeNode root) {
if (root == null) {
return 0;
}
int leftCount = countNodes1(root.left);
int rightCount = countNodes1(root.right);
int resultCount = leftCount + rightCount + 1;
return resultCount;
}
3、DSF前序遍历
/**
* 222. 完全二叉树的节点个数---DSF前序遍历
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes2(TreeNode root) {
if (root == null) {
return 0;
}
int count = 1;
int leftCount = countNodes2(root.left) + count;
int rightCount = countNodes2(root.right) + leftCount;
return rightCount;
}
4、DSF中序遍历
/**
* 222. 完全二叉树的节点个数---DSF中序遍历
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes3(TreeNode root) {
if (root == null) {
return 0;
}
int leftCount = countNodes3(root.left);
int count = 1 + leftCount;
int rightCount = countNodes3(root.right) + count;
return rightCount;
}
5、DSF后序栈遍历
/**
* 222. 完全二叉树的节点个数---DSF后序栈遍历
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes4(TreeNode root) {
int result = 0;
Stack<TreeNode> stack = new Stack<>();
if (root == null) {
return result;
}
stack.add(root);
while (!stack.isEmpty()) {
TreeNode node = stack.peek();
if (node != null) {
node = stack.pop();
stack.add(node);
stack.add(null);
if (node.right !=null){
stack.add(node.right);
}
if (node.left !=null){
stack.add(node.left);
}
} else {
stack.pop();//弹出空指针
node = stack.pop();//弹出节点
result++;
}
}
return result;
}
6、DSF后序满二叉树后序遍历
因为是完全二叉树,必然左右子树中有一个是满二叉树,因为可以使用满二叉树求节点数量。
1、定义左右指针和左右深度,用于记录左右外层子树深度。
2、循环左右子树深度,得到左右深度数量
3、如果左右深度一直则使用满二叉树公式返回节点数量
4、递归调用左右节点,最后累计相加再上中间节点数返回即可
注:为啥没有左右深度不一致逻辑,其实已经隐藏在递归调用里了,如果左右子树深度不一致,那么必然右子树为0,左子树为1,中间节点为1+1;那就是普通后序递归逻辑。而代码最后就是普通后序递归逻辑。
/**
* 222. 完全二叉树的节点个数---DSF后序满二叉树后序遍历
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~2^h个节点。
*
* @param root
* @return
*/
public int countNodes5(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth = 0, rightDepth = 0;
while (left != null) {
left = left.left;
leftDepth++;
}
while (right != null) {
right = right.right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1;
}
int leftSum = countNodes5(root.left);
int rightSum = countNodes5(root.right);
int result = leftSum + rightSum +1;
return result;
}