LeetCode题目:
- [110. 平衡二叉树](#110. 平衡二叉树)
- [257. 二叉树的所有路径](#257. 二叉树的所有路径)
- [404. 左叶子之和](#404. 左叶子之和)
- [222. 完全二叉树的节点个数](#222. 完全二叉树的节点个数)
- [3375. 使数组的值全部为 K 的最少操作次数(每日一题)](#3375. 使数组的值全部为 K 的最少操作次数(每日一题))
其他:
110. 平衡二叉树
跳转:
学习: 代码随想录公开讲解
问题:
给定一个二叉树,判断它是否是 平衡二叉树
平衡二叉树 是指该树所有节点的左右子树的高度相差不超过 1。
提示:
- 树中的节点数在范围
[0, 5000]
内 - − 1 0 4 < = N o d e . v a l < = 1 0 4 -10^4 <= Node.val <= 10^4 −104<=Node.val<=104

思路:
平衡二叉树左右子树高度差不超过1
这题要求高度差,所以应该使用后序遍历,毕竟只有先知道高度才能进一步比较.
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(递归法):
java
class Solution {
int deep(TreeNode root,int deep){
if(root==null) return deep;
int a = deep(root.left,deep+1);
int b = deep(root.right,deep+1);
if(Math.abs(a-b)>1) return -1;
return Math.max(a,b);
}
public boolean isBalanced(TreeNode root) {
return deep(root,1)>0;
}
}
代码(迭代法):
java
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode tmp = stack.pop();
if (tmp == null) {
tmp = stack.pop();
int a = tmp.left==null?0:tmp.left.val;
int b = tmp.right==null?0:tmp.right.val;
if(Math.abs(a-b)>1) return false;
tmp.val = Math.max(a,b)+1;
} else {
stack.push(tmp);
stack.push(null);
if (tmp.right != null)
stack.push(tmp.right);
if (tmp.left != null)
stack.push(tmp.left);
}
}
return true;
}
}
257. 二叉树的所有路径
跳转:
学习: 代码随想录公开讲解
问题:
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
提示:
- 树中节点的数目在范围
[1, 100]
内 -100 <= Node.val <= 100

思路:
这道题是只要遍历到叶子节点就存储一下路径,所以用前序遍历先判断是否为叶子节点比较合适.
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码(递归回溯):
java
class Solution {
List<String> ans = new ArrayList<>();
void getPath(TreeNode root, StringBuilder s) {
if (root == null)
return;
String tmp = Integer.toString(root.val);
if (root.left == null && root.right == null) {
ans.add(s.append(tmp).toString());
s.delete(s.length() - tmp.length(), s.length());
return;
}
if (root.left != null) {
s.append(tmp);
s.append("->");
getPath(root.left, s);
s.delete(s.length() - 2 - tmp.length(), s.length());
}
if (root.right != null) {
s.append(tmp);
s.append("->");
getPath(root.right, s);
s.delete(s.length() - 2 - tmp.length(), s.length());
}
}
public List<String> binaryTreePaths(TreeNode root) {
getPath(root, new StringBuilder());
return ans;
}
}
代码(迭代法):
java
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> ans = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
Stack<String> str = new Stack<>();
stack.push(root);
str.push(Integer.toString(root.val));
while (!stack.isEmpty()) {
TreeNode tmp = stack.pop();
String s = str.pop();
if (tmp.left == null && tmp.right == null) {
ans.add(s);
continue;
}
if (tmp.right != null) {
stack.push(tmp.right);
str.push(s + "->" + tmp.right.val);
}
if (tmp.left != null) {
stack.push(tmp.left);
str.push(s + "->" + tmp.left.val);
}
}
return ans;
}
}
404. 左叶子之和
跳转:
学习: 代码随想录公开讲解
问题:
给定二叉树的根节点 root
,返回所有左叶子之和。
提示:
- 节点数在
[1, 1000]
范围内 -1000 <= Node.val <= 1000

思路:
这题只需要判断每个节点的左子节点是不是叶子节点就好了,前中后序甚至层序遍历都可以做.
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(前序递归):
java
class Solution {
int ans = 0;
void handle(TreeNode root){
if(root==null) return;
TreeNode tmp = root.left;
if(tmp!=null){
if(tmp.left==null&&tmp.right==null)
ans+=root.left.val;
else
handle(root.left);
}
handle(root.right);
}
public int sumOfLeftLeaves(TreeNode root) {
handle(root);
return ans;
}
}
代码(中序迭代):
java
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int ans = 0;
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
while (root!=null) {
stack.push(root);
root = root.left;
if(root==null) break;
if (root.left == null && root.right == null) {
ans += root.val;
}
}
root = stack.pop();
root = root.right;
}
return ans;
}
}
222. 完全二叉树的节点个数
跳转:
学习: 代码随想录公开讲解
问题:
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层(从第 0 层开始),则该层包含 1~ 2h
个节点。
提示:
- 树中节点的数目范围是
[0, 5 * 104]
0 <= Node.val <= 5 * 104
- 题目数据保证输入的树是 完全二叉树
进阶: 遍历树来统计节点是一种时间复杂度为 O(n)
的简单解决方案。你可以设计一个更快的算法吗?

思路:
遍历计数即可,前中后层序都可以
当然,因为是完全二叉树,所以可以利用完全二叉树的性质来简化遍历
因为完全二叉树紧密排列,所以其左右子树一定至少有一个满二叉树,如果两颗都是满二叉树就用公式2^n-1,否则继续分左右子树
可以算作是一种二分,如果数据量大对时间效率的提升还是很可观的
复杂度:
- 时间复杂度:O(n)
- 空间复杂度:O(log n)
代码(遍历递归):
java
class Solution {
int getChildren(TreeNode root){
if(root==null) return 0;
int a = getChildren(root.left);
int b = getChildren(root.right);
return a+b+1;
}
public int countNodes(TreeNode root) {
return getChildren(root);
}
}
复杂度:
- 时间复杂度:O(log n × log n)
- 空间复杂度:O(log n)
代码(优化递归):
java
class Solution {
public int countNodes(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;
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
3375. 使数组的值全部为 K 的最少操作次数(每日一题)
问题
给你一个整数数组 nums
和一个整数 k
。
如果一个数组中所有 严格大于 h
的整数值都 相等 ,那么我们称整数 h
是 合法的 。
比方说,如果 nums = [10, 8, 10, 8]
,那么 h = 9
是一个 合法 整数,因为所有满足 nums[i] > 9
的数都等于 10 ,但是 5 不是 合法 整数。
你可以对 nums
执行以下操作:
- 选择一个整数
h
,它对于 当前nums
中的值是合法的。 - 对于每个下标
i
,如果它满足nums[i] > h
,那么将nums[i]
变为h
。
你的目标是将 nums
中的所有元素都变为 k
,请你返回 最少 操作次数。如果无法将所有元素都变 k
,那么返回 -1 。
提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100
1 <= k <= 100
思路:
由题,每次操作可以将最大的整数转化成第二大的整数.
并且只能从大到小进行转换.
使数组值全部为k其实就是让我们求数组中有多少种比k大的整数.
并且如果存在比k小的数一定不合法.
故这题直接使用哈希计数,并判断一下非法情况即可
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码:
java
class Solution {
public int minOperations(int[] nums, int k) {
int[] hash = new int[101];
int ans = 0;
for (int i : nums) {
if (i < k)
return -1;
if (i!=k&&hash[i] == 0) {
ans++;
hash[i]++;
}
}
return ans;
}
}
总结
练习了二叉树的遍历,复习了平衡二叉树,完全二叉树,满二叉树等特殊二叉树的性质
往期打卡
*[222. 完全二叉树的节点个数]: LeetCode
*[257. 二叉树的所有路径]: LeetCode
*[3375. 使数组的值全部为 K 的最少操作次数]: LeetCode
*[404. 左叶子之和]: LeetCode
*[110. 平衡二叉树]: LeetCode