碎碎念:
参考:代码随想录
110.平衡二叉树
题目链接
思想
高度是节点距离叶子节点的距离。——后序
深度是节点距离根节点的距离。——前序
本题使用后序遍历。
递归三部曲:
- 参数和返回值:要判断左右子树的高度,所以返回值为int类型。要是判断当前的树已经不是平衡二叉树了就向上返回-1.
- 空节点返回0.
- 单层递归的逻辑:
左:递归 再看得到的返回值是不是-1
右:递归 再看得到的返回值是不是-1
中:两个子树都是平衡二叉树了,接下来要看左右子树的高度差,高度差>1,return -1;符高度差<=1返回1+max(右子树的高度,左子树的高度)。
题解
class Solution {
public:
int getHeight(TreeNode* node) {
if (node == NULL) return 0;
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
};
class Solution:
def getHeight(self, node):
if node == None:
return 0;
leftHeight = self.getHeight(node.left)
if leftHeight == -1:
return -1
rightHeight = self.getHeight(node.right)
if rightHeight == -1:
return -1
return -1 if abs(leftHeight-rightHeight) > 1 else 1+max(leftHeight, rightHeight)
def isBalanced(self, root: Optional[TreeNode]) -> bool:
return False if self.getHeight(root) == -1 else True
反思
257. 二叉树的所有路径
题目链接
思想
应该用前序遍历,因为使用前序遍历才会输出路径。
**回溯:**比如上图,把5弹出去,把2弹出去,这个过程就是回溯。
递归三部曲:
- 返回值参数path单条路径result string类型最后的结果
- 终止条件:左右孩子都为空(遍历到了叶子节点),把path转成字符串再加入result。 return
- 单层逻辑:为了防止漏掉叶子节点,所以路径收集的操作要放到终止条件的上面。左:如果左节点不为空,向左遍历,回溯;右:如果右节点不为空,向右遍历,回溯。
注意常见的题解代码里隐含了回溯。
题解
// C++比较细节的代码写法
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
path.push_back(cur->val); // 放在这里防止漏掉叶子节点
if (cur->left == NULL && cur->right == NULL) {
string sPath;
for (int i = 0; i < path.size() - 1; i++) {
sPath += to_string(path[i]);
sPath += "->";
}
sPath += to_string(path[path.size() - 1]);
result.push_back(sPath);
return;
}
if (cur->left) {
traversal(cur->left, path, result);
path.pop_back(); // 回溯
}
if (cur->right) {
traversal(cur->right, path, result);
path.pop_back(); // 回溯
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
vector<int> path;
if (root == NULL) return result;
traversal(root, path, result);
return result;
}
};
// C++常见的解法 隐含了回溯
class Solution {
private:
void traversal(TreeNode* cur, string path, vector<string>& result) {
path += to_string(cur->val); // 中
if (cur->left == NULL && cur->right == NULL) {
result.push_back(path);
return;
}
if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯隐含在path+"->" 执行完递归函数以后,path依然是之前的数,相当于回溯
if (cur->right) traversal(cur->right, path + "->", result); // 右
}
public:
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
string path;
if (root == NULL) return result;
traversal(root, path, result);
return result;
}
};
# python
class Solution:
def traversal(self, cur, path, result):
path.append(cur.val)
if not cur.left and not cur.right:
sPath = '->'.join(map(str, path)) # map 函数,将 path 列表中的每个元素转换为字符串 这里是处理成要求的输出格式
result.append(sPath)
return
if cur.left:
self.traversal(cur.left, path, result)
path.pop() # 回溯
if cur.right:
self.traversal(cur.right, path, result)
path.pop() # 回溯
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
result = []
path = []
if not root:
return result
self.traversal(root, path, result)
return result
反思
注意看是怎么回溯的,也注意积累一下字符串的处理。
404.左叶子之和
题目链接
思想

遍历到9的时候可以知道它是不是叶子节点,但是无法判断是不是为父节点的左孩子。所以要通过它的父节点来判断。
本题应该使用后序遍历。
递归三部曲:
- 参数和返回值
- 终止条件 如果node==null 返回0; 如果是叶子节点,返回0
- 单层操作: 左:递归左边,如果当前节点的左孩子不为空,左孩子还是叶子节点,得到leftnum;右:递归右子树;中:返回左子树符合条件的和+右子树符合条件的和。
题解
// cpp
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == NULL) return 0;
int leftValue = sumOfLeftLeaves(root->left);
if (root->left && !root->left->left && !root->left->right)
leftValue = root->left->val;
int rightValue = sumOfLeftLeaves(root->right);
return leftValue + rightValue;
}
};
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
leftValue = self.sumOfLeftLeaves(root.left)
if root.left and not root.left.left and not root.left.right:
leftValue = root.left.val
rightValue = self.sumOfLeftLeaves(root.right)
return leftValue + rightValue
222.完全二叉树的节点个数
题目链接
思想
普通二叉树直接遍历就行,这道题强调了完全二叉树,要求我们尽量使用完全二叉树的特性。
**普通二叉树解法:**后序遍历
利用完全二叉树特性的解法:
满二叉树是一种特殊的二叉树,其中每个节点要么没有子节点,要么恰好有两个子节点。换句话说,除了叶子节点外,每个节点都有两个子节点。满二叉树的一个特性是,如果其深度为 (d),则总共有 (2^{d} - 1) 个节点。
完全二叉树是指除了最后一层外,其他每一层的节点数都达到最大可能数,并且最后一层的节点都集中在左边。对于完全二叉树,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照满二叉树的节点数计算公式来计算。
**如何判断一个子树是否为满二叉树:**分别计算左侧深度和右侧深度,如果两数相等,说明它是满二叉树,就可以用公式计算。
这种方式利用了满二叉树的特性,也避免遍历没有必要遍历的节点。
递归三部曲:
- 返回值和参数
- 终止条件: NULL 以及找到满二叉树(分别计算左侧深度和右侧深度,然后比较深度,相等就直接用公式计算节点数量)
- 单层逻辑:向左遍历,向右遍历,返回左子树节点数量+右子树节点数量+1
这种方式并没有把所有的节点都遍历一遍。
题解
// 普通二叉树解法 后序遍历 cpp
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == NULL) return 0;
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
# 普通二叉树解法 后序遍历 python
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
return 1 + self.countNodes(root.left) + self.countNodes(root.right)
// 利用完全二叉树性质解法 cpp
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == NULL) return 0;
int leftDepth = 1, rightDepth = 1;
TreeNode* left = root->left;
TreeNode* right = root->right;
while (left) {
left = left->left;
leftDepth++;
}
while (right) {
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (1 << leftDepth) - 1; // 左移1位是x2 左移leftDepth位是x2^(leftDepth)
}
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
# 利用完全二叉树性质的解法
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
leftDepth = 1
rightDepth = 1
left = root.left
right = root.right
while left:
left = left.left
leftDepth += 1
while right:
right = right.right
rightDepth += 1
if leftDepth == rightDepth:
return (1 << leftDepth) - 1
return self.countNodes(root.left) + self.countNodes(root.right) + 1
反思
左移那里绕了一下。要记清楚满二叉树、完全二叉树的定义和性质。
2124

被折叠的 条评论
为什么被折叠?



