代码随想录算法训练营第十二天
LeetCode题目:
- 226. 翻转二叉树
- 101. 对称二叉树
- 104. 二叉树的最大深度
- 111. 二叉树的最小深度
- 3396. 使数组元素互不相同所需的最少操作次数(每日一题)
其他:
今日总结
往期打卡
226. 翻转二叉树
跳转: 226. 翻转二叉树
问题:
给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
提示:
- 树中节点数目范围在
[0, 100]
内 -100 <= Node.val <= 100
思路:
自底向上每个节点交换左右节点即可,所以可以后序遍历做子树交换
当然前序遍历,层序遍历都是没有什么问题的
但如果中序遍历,因为交换前已经遍历了一棵子数,交换后还要沿着遍历过的方向遍历子树,所以编码实现上稍微有些不同
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(后序遍历):
class Solution {
void reverse(TreeNode root) {
if (root == null) return;
reverse(root.left);
reverse(root.right);
swap(root);
}
void swap(TreeNode root){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
public TreeNode invertTree(TreeNode root) {
reverse(root);
return root;
}
}
代码(前序遍历):
class Solution {
void reverse(TreeNode root) {
if (root == null) return;
swap(root);
reverse(root.left);
reverse(root.right);
}
void swap(TreeNode root){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
public TreeNode invertTree(TreeNode root) {
reverse(root);
return root;
}
}
代码(中序遍历):
class Solution {
void reverse(TreeNode root) {
if (root == null) return;
reverse(root.left);
swap(root);
reverse(root.left);
}
void swap(TreeNode root){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
public TreeNode invertTree(TreeNode root) {
reverse(root);
return root;
}
}
代码(层序遍历):
class Solution {
void swap(TreeNode root){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
public TreeNode invertTree(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode tmp = queue.poll();
if(tmp==null) continue;
swap(tmp);
queue.add(tmp.left);
queue.add(tmp.right);
}
}
return root;
}
}
101. 对称二叉树
跳转: 101. 对称二叉树
问题:
给你一个二叉树的根节点 root
, 检查它是否轴对称。
提示:
- 树中节点数目在范围
[1, 1000]
内 -100 <= Node.val <= 100
思路:
可以看作比较左右两棵子树,判断是否一二叉树左子树等于另一二叉树右子树.
所以只需要反着比较就可以了,这里使用前序遍历和层序遍历,可以在发现不相等时即返回,不必等待遍历完成.
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(递归):
class Solution {
boolean compare(TreeNode tree1,TreeNode tree2){
if(tree1==null&&tree2==null){
return true;
}
if(tree1==null||tree2==null) return false;
if(tree1.val!=tree2.val) return false;
boolean a = compare(tree1.left,tree2.right);
boolean b = compare(tree1.right,tree2.left);
return a&b;
}
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return compare(root.left , root.right);
}
}
代码(迭代):
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root.left);
queue.add(root.right);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i+=2){
TreeNode a = queue.poll();
TreeNode b = queue.poll();
if(a==null&&b==null) continue;
if(a==null||b==null) return false;
if(a.val!=b.val) return false;
queue.add(a.left);
queue.add(b.right);
queue.add(a.right);
queue.add(b.left);
}
}
return true;
}
}
104. 二叉树的最大深度
跳转: 104. 二叉树的最大深度
问题:
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
提示:
- 树中节点的数量在
[0, 104]
区间内。 -100 <= Node.val <= 100
思路:
遍历一遍,到null记录一下深度,最大值就是最大深度
怎么遍历都可以,这里使用递归遍历(因为不用处理节点信息,所以不必区分前中后序,可以看作深搜)
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(递归遍历):
class Solution {
int getMaxDeep(TreeNode root){
if(root==null){
return 0;
}
return Math.max(1+getMaxDeep(root.left),1+getMaxDeep(root.right));
}
public int maxDepth(TreeNode root) {
return getMaxDeep(root);
}
}
111. 二叉树的最小深度
跳转: 111. 二叉树的最小深度
问题:
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
**说明:**叶子节点是指没有子节点的节点。
提示:
- 树中节点数的范围在
[0, 105]
内 -1000 <= Node.val <= 1000
思路:
最小遍历需要注意找最上层的叶子节点,如果要保持判断条件为null返回,就要进一步分类处理
当然一遍遍历肯定是可以解决的
这道题比较适合使用层序遍历
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
代码(递归遍历):
class Solution {
int getMinDeep(TreeNode root){
if(root==null){
return 0;
}
int leftDepth = getMinDeep(root.left)+1;
int rightDepth = getMinDeep(root.right)+1;
if(root.left==null) return rightDepth;
if(root.right==null) return leftDepth;
return Math.min(rightDepth,leftDepth);
}
public int minDepth(TreeNode root) {
return getMinDeep(root);
}
}
代码(层序遍历):
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int depth = 0;
while(!queue.isEmpty()){
int size = queue.size();
depth++;
for(int i=0;i<size;i++){
TreeNode tmp = queue.poll();
if(tmp==null) continue;
if(tmp.left==null&&tmp.right==null) return depth;
queue.add(tmp.left);
queue.add(tmp.right);
}
}
return depth;
}
}
3396. 使数组元素互不相同所需的最少操作次数(每日一题)
跳转: 3396. 使数组元素互不相同所需的最少操作次数
问题
给你一个整数数组 nums
,你需要确保数组中的元素 互不相同 。为此,你可以执行以下操作任意次:
- 从数组的开头移除 3 个元素。如果数组中元素少于 3 个,则移除所有剩余元素。
注意: 空数组也视作为数组元素互不相同。返回使数组元素互不相同所需的 最少操作次数 。
提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100
思路:
可以双指针+哈希(如果数字范围再大些有负数也可以用Map存偏移)
这个思路是用慢指针存储维持哈希各值唯一的最小开头位置
当然,因为题目是只能从开头操作,所以逆序遍历的思路更好
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码(逆序遍历+哈希):
class Solution {
public int minimumOperations(int[] nums) {
int n = nums.length;
int[] hash = new int[101];
while(n-->0){
int tmp = nums[n];
if(hash[tmp]>0) return n/3+1;
hash[tmp]++;
}
return 0;
}
}
代码(双指针+哈希):
class Solution {
public int minimumOperations(int[] nums) {
int n = nums.length;
int[] hash = new int[101];
while(n-->0){
int tmp = nums[n];
if(hash[tmp]>0) return n/3+1;
hash[tmp]++;
}
return 0;
}
}
总结
今天主要应用了一下二叉树的四种遍历方式,然后从每日一题中复习了一下哈希.
往期打卡
代码随想录算法训练营第一天
代码随想录算法训练营第二天
代码随想录算法训练营第三天
代码随想录算法训练营第四天
代码随想录算法训练营周末一
代码随想录算法训练营第五天
代码随想录算法训练营第六天
代码随想录算法训练营第七天
代码随想录算法训练营第八天
代码随想录算法训练营第九天
代码随想录算法训练营第十天
代码随想录算法训练营周末二
代码随想录算法训练营第十一天