一、完全二叉树的节点个数
题目链接:222. 完全二叉树的节点个数
/**
* <pre>
* 1.二分查找+位运算
* 2.递归:如果子树是完全二叉树则直接返回子树的节点数,如果不是完全二叉树则继续判断其左右子树
* </pre>
*
* @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
* @date 2023/1/15 10:54
*/
public class 完全二叉树的节点个数222 {
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode node = root;
int h = 0;
while (node.left != null) {
h++;
node = node.left;
} // 求出最大高度
int left = 1 << h, right = (1 << (h+1)) - 1; // 最下一层节点的标号
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (check(root, h, mid)) {
// 该节点存在,则往右查找
left = mid + 1;
} else {
right = mid - 1;
}
}
return right;
}
public boolean check(TreeNode root, int height, int index) {
int bits = 1 << (height-1);
TreeNode node = root;
while (node != null && bits > 0) {
// &运算可以用来求一个数中的指定位,将要判断的那一位置为1,其他位为0,然后用这个数和指定数想与,结果如果为0就说明对应位置为0,结果如果不为0就说明对应位置为1
// 此处我们要判断index的第二位到结束的每一位是0还是1来决定是往左走还是往右走,这里用bits来控制
// 最开始bits=1<<(height-1)其实就是一个首位为1(因为是height-1所以这里的首位对应的是index的第二位),其他都为0的数
// 然后每次判断后就对bits右移1位,即然后1后移以判断index后面的位是否为1
// 比如index=5,即101,首位不用看,第二位0就说明从根节点先像左走,第三位为1就说明第二步是往右走即可到达结点5
if ((index & bits) == 0) {
node = node.left;
} else {
node = node.right;
}
bits >>= 1;
}
return node != null;
}
public int countNodes2(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode left = root.left;
TreeNode right = root.right;
int leftHeight = 0, rightHeight = 0;
while (left != null) {
left = left.left;
leftHeight++;
}
while (right != null) {
right = right.right;
rightHeight++;
}
if (leftHeight == rightHeight) {
return (1 << (leftHeight+1)) - 1;
}
return countNodes2(root.left) + countNodes2(root.right) + 1;
}
}
二、平衡二叉树
题目链接:110. 平衡二叉树
/**
* <pre>
* 1.自顶向下递归,不断求左右节点的高度判断差值是否大于1(每个节点的高度会被重复计算)
* 2.自底向上递归,采用后续遍历,从最下的节点开始,求其左右节点高度,判断是否平衡,如果不平衡则整棵树不平衡,如果平衡则继续往上判断
* </pre>
*
* @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
* @date 2023/1/15 14:33
*/
public class 平衡二叉树110 {
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
}
if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) { // 判断当前节点左右子树是否平衡
return false;
}
return isBalanced(root.left) && isBalanced(root.right); // 如果平衡则继续往下判断左右子节点
}
public int getHeight(TreeNode treeNode) {
if (treeNode == null) {
return 0;
}
return Math.max(getHeight(treeNode.left), getHeight(treeNode.right)) + 1;
}
public boolean isBalanced2(TreeNode root) {
return getHeight2(root) >= 0;
}
public int getHeight2(TreeNode treeNode) {
if (treeNode == null) {
return 0;
}
int leftHeight = getHeight2(treeNode.left);
int rightHeight = getHeight2(treeNode.right);
if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
return -1; // 相当于后续遍历,到最下面一个节点后判断其左右子树是否平衡,不平衡则返回-1,如果子节点的高度已经是-1了则肯定不平衡了直接返回-1
}
return Math.max(leftHeight, rightHeight) + 1;
}
}
三、二叉树的所有路径
题目链接:257. 二叉树的所有路径
/**
* <pre>
* 1.深度优先搜索
* 2.广度优先搜索
* </pre>
*
* @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
* @date 2023/1/15 23:46
*/
public class 二叉树的所有路径227 {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
traversal(res, new StringBuilder(), root);
return res;
}
public void traversal(List<String> res, StringBuilder path, TreeNode root) {
TreeNode left = root.left;
TreeNode right = root.right;
if (left == null && right == null) {
res.add(path.toString() + root.val); // 不能用path.append后再toString,会导致path值改变
return;
}
int len = path.length();
path.append(root.val).append("->");
if (left != null) {
traversal(res, path, left);
}
if (right != null) {
traversal(res, path, right);
}
path.delete(len, path.length()); // 回溯
}
public List<String> binaryTreePaths2(TreeNode root) {
List<String> res = new ArrayList<>();
Queue<TreeNode> nodeQueue = new LinkedList<>();
Queue<String> pathQueue = new LinkedList<>();
nodeQueue.offer(root);
pathQueue.offer(String.valueOf(root.val));
while (!nodeQueue.isEmpty()) {
TreeNode treeNode = nodeQueue.poll();
String path = pathQueue.poll();
if (treeNode.left == null && treeNode.right == null) {
res.add(path);
}
if (treeNode.left != null) {
nodeQueue.offer(treeNode.left);
pathQueue.offer(path + "->" + treeNode.left.val);
}
if (treeNode.right != null) {
nodeQueue.offer(treeNode.right);
pathQueue.offer(path + "->" + treeNode.right.val);
}
}
return res;
}
}
四、左叶子之和
题目链接:404. 左叶子之和
/**
* <pre>
* 1.深搜
* 2.广搜
* </pre>
*
* @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
* @date 2023/1/15 23:46
*/
public class 左叶子之和404 {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + (root.left != null && root.left.left == null && root.left.right == null ? root.left.val : 0); // 等于左子树左叶子节点和+右子树左叶子节点和
}
public int sumOfLeftLeaves2(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int sum = 0;
while (!queue.isEmpty()) {
TreeNode poll = queue.poll();
if (poll.left != null) {
if (poll.left.left == null && poll.left.right == null) {
sum += poll.left.val;
} else {
queue.offer(poll.left);
}
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
return sum;
}
}