碎碎念:加油!!!!
参考:代码随想录
226.翻转二叉树
题目链接
思想
注意本题应该交换指针,而不是数值。本题用前序或者后序最合适。
递归三部曲:
- 确定递归函数的返回值和参数
- 确定终止条件:root == NULL时return root
- 处理逻辑:交换root的左孩子和右孩子
**为什么不用中序遍历:**中序的顺序是左中右,先遍历了左子树,回到root后左右子树交换了,那么遍历右子树实际上还是遍历原来的左子树,所以说中序不合适。要写的话也行,就是后面的要改成还处理左子树。
题解
// 前序遍历
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if root == None:
return root
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
反思
写递归的时候要把握住递归的三步。写这道题的时候要清楚自己用的遍历方法,这题写中序遍历的时候有特殊的写法。
101. 对称二叉树
题目链接
思想
如果左子树和右子树可以相互翻转,就说明这是一个对称二叉树。
看一个树是否为对称二叉树:比较的时候应该比较外侧的节点是否相等,内侧的节点是否相等。
这道题只能使用后序,顺序是左右中,因为我们要不断收集左右孩子的信息返回上一个节点,才能知道左右两边比较的结果。
递归三部曲:
- 传入的参数:左子树的头结点,右子树的头结点
- 终止条件:有以下几种情况
3. 递归逻辑:值不为空,且相等,则继续向下遍历。判断相等应该看对称的点位,也就是外侧和外侧,内侧和内侧比较。
左节点的左孩子 右节点的右孩子 比较
左节点的右孩子 右节点的左孩子 比较
只有都返回true的时候,才返回true。
题解
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false;
else return compare(left->left, right->right) && compare(left->right, right->left);
}
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
return compare(root->left, root->right);
}
};
class Solution:
def compare(self, left, right):
if left == None and right != None: return False
elif left != None and right == None: return False
elif left == None and right == None: return True
elif left.val != right.val: return False
else: return self.compare(left.left, right.right) and self.compare(left.right, right.left)
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
return self.compare(root.left, root.right)
反思
二叉树的题目确定遍历顺序非常重要。
104.二叉树的最大深度
题目链接
思想
区分深度和高度
深度:二叉树里任意一个节点到根节点的距离——前序
高度:二叉树任意一个节点到叶子节点的距离——后序
一般题解都是后序遍历,因为根节点的高度就是最大深度。真正求深度应该用前序遍历。
本题还是求的根节点的高度(也就是最大深度),所以用的后序遍历。
递归三部曲:
- 确定递归函数的参数和返回值
- 确定终止条件 遇到空了 高度应该是0
- 逻辑:
递归左
递归右
中:1 + max
题解
class Solution {
public:
int getdepth(TreeNode* node) {
if (node == NULL) return 0;
// 后序遍历
int leftdepth = getdepth(node->left);
int rightdepth = getdepth(node->right);
return 1 + max(leftdepth, rightdepth);
}
int maxDepth(TreeNode* root) {
return getdepth(root);
}
};
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0;
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
反思
要理解本题的本质是后序遍历,上面题解给出的精简解法掩盖了后序遍历的本质,其实实际上也是后序遍历。
111.二叉树的最小深度
题目链接
思想
**二叉树的最小深度:**根节点到叶子节点的最小距离。
和上一题有点类似,只是把取最大值变为取最小值,上一题用后序求了高度,本题也可以用后序求高度,得到深度。其实前序遍历才是个求深度过程。
写前序遍历的代码比后序的稍微麻烦点,前序代码见代码随想录。
递归三部曲:
- 确定返回值和参数
- 确定终止条件:node==NULL 返回0
- 递归逻辑:左右中
注意这里写中间的逻辑的时候不能直接返回min+1,比如上图,根据题目给出的定义,最小深度应该是3。也就是说要处理当孩子有NULL的情况。
题解
class Solution {
public:
int getDepth(TreeNode* node) {
if (node == NULL) return 0;
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
if (node->left != NULL && node->right == NULL) return 1 + leftDepth;
if (node->left == NULL && node->right != NULL) return 1 + rightDepth;
return 1 + min(leftDepth, rightDepth);
}
int minDepth(TreeNode* root) {
return getDepth(root);
}
};
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root==None:
return 0
if root.left == None and root.right != None:
return 1 + self.minDepth(root.right)
if root.left != None and root.right == None:
return 1 + self.minDepth(root.left)
return 1 + min(self.minDepth(root.left), self.minDepth(root.right))
反思
注意不能直接返回min+1,有埋伏!