目录
LeetCode 104. 二叉树的最大深度 111. 二叉树的最小深度
LeetCode 226. 翻转二叉树
题目链接:LeetCode 226. 翻转二叉树
思想:本题非常简单,要翻转一个二叉树,只需要在遍历过程中,把当前节点的左右节点交换一下位置就完成啦。
代码如下:
void bianli(TreeNode* cur){
if (!cur) return;
TreeNode* temp = cur->left;
cur->left = cur->right;
cur->right = temp;
bianli(cur->left);
bianli(cur->right);
}
TreeNode* invertTree(TreeNode* root) {
bianli(root);
return root;
}
LeetCode 101. 对称二叉树
题目链接:LeetCode 101. 对称二叉树
思想:二叉树的题目普遍涉及到遍历,所以每一题都要思考要采取怎么样的遍历方式才适合本题。很明显,本题需要判断一个二叉树的对称性,就必须两个左右节点同时进行比较,那么就需要左右连着一起的一个遍历方式,那么只能采取后序遍历,左右中了。同时遍历左子树,采取左右中;遍历右子树,采取右左中。这样才能对上对称性。同时需要把左右子树的对称性作为返回值,所以前序遍历也不行。
最后,需要明确不对称的情况:
- 左子树的节点存在,右子树的节点为空;
- 左子树的节点为空,右子树的节点存在;
- 左右子树的节点都存在,但值不同;
还需要明确一种情况就是:两个节点都不存在那么就是对称的。
代码如下:
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;
bool inside = compare(left->right, right->left);
bool outside = compare(left->left, right->right);
return inside && outside;
}
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return compare(root->left, root->right);
}
LeetCode 104. 二叉树的最大深度 111. 二叉树的最小深度
题目链接:LeetCode 104. 二叉树的最大深度、LeetCode 111. 二叉树的最小深度
思想:可以采取昨天的层序遍历方法,最大深度就遍历到低,最小深度就遍历到第一个叶子结点,也就是说第一个没有左右节点的节点。所以这里就不过多赘述。
LeetCode 110. 平衡二叉树
题目链接:LeetCode 110. 平衡二叉树
思想:本题确实有点坑,我最开始以为是左右子树的深度不超过一,结果是所有节点之间的深度不超过一。所以这里我们再过一遍概念。
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
- 二叉树节点的高度:指从该节点到叶子结点的最长简单路径边的条数。
很明显,求深度要从上到下查,所以需要前序遍历,而高度只能从下到上查,所以只能后序遍历。但深度和高度是一个相对概念,深度大,高度小;深度小,高度大。所以两个节点之间深度不超过一,也可以转换成两个节点之间高度不超过一。所以主要就是求当前节点的左右子树的高度,如果左右子树高度之差小于等于1就返回当前二叉树的高度。
代码如下:
int getDepth(TreeNode* cur){
if (!cur) return 0;
int leftDepth = getDepth(cur->left);
if (leftDepth == -1) return -1;
int rightDepth = getDepth(cur->right);
if (rightDepth == -1) return -1;
return abs(rightDepth - leftDepth) > 1 ? -1 : 1 + max(rightDepth, leftDepth);
}
bool isBalanced(TreeNode* root) {
return getDepth(root) == -1 ? false : true;
}
LeetCode 257. 二叉树的所有路径
思想:这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
首先,我们需要往参数里放根节点,存放需要回溯节点的数组以及用来返回最终结果的数组。其次,本题的终止条件是找到叶子结点就开始处理。处理的逻辑就是,new一个string,然后遍历用于回溯的数组,将里面的值拼接成“x->x->x”的样子即可。接下来就是要遍历左右节点了,如果左右节点存在的话就继续遍历,并在遍历结束之后将回溯数组的最后元素弹出即可,达成回溯的效果。
代码如下:
void rootPathtoLeef(TreeNode* cur, vector<int>& path, vector<string>& result){
path.push_back(cur->val);
if (cur->left == NULL && cur->right == NULL){
string str = "";
for (int i = 0; i < path.size() - 1; i++){
str += to_string(path[i]);
str += "->";
}
str += to_string(path[path.size() - 1]);
result.push_back(str);
return;
}
if (cur->left){
rootPathtoLeef(cur->left, path, result);
path.pop_back();
}
if (cur->right){
rootPathtoLeef(cur->right, path, result);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;
vector<string> result;
if (!root) return result;
rootPathtoLeef(root, path, result);
return result;
}
LeetCode 404. 左叶子之和
题目链接:LeetCode 404. 左叶子之和
思想:竟然有404的题目,不应该找不到吗?哈哈哈哈,开个玩笑。本题也特别简单,就判断左叶子就行了。如何判断左叶子就需要父亲节点才行。所以这个稍微带来点麻烦。
代码如下:
void bianli(TreeNode* cur, int& sum){
if (!cur) return;
if (cur->left && cur->left->left == NULL && cur->left->right == NULL){
sum += cur->left->val;
bianli(cur->left, sum);
}
if (cur->left) bianli(cur->left, sum);
if (cur->right) bianli(cur->right, sum);
}
int sumOfLeftLeaves(TreeNode* root) {
if(!root) return 0;
int sum = 0;
bianli(root, sum);
return sum;
}
LeetCode 222. 完全二叉树的节点个数
思想:本题可以用普通版的遍历,采用O(n)的时间复杂度就能数清楚每种树的节点,包含完全二叉树。那既然这样,为什么这题不叫二叉树的节点个数呢。所以这题可以采用另一些方法来数。
完全二叉树里面,又可以分为很多个小的满二叉树,所以可以通过数里面有多少个满二叉树来降低时间复杂度。如果目前节点下的子树不是满二叉树,就递归其左右孩子,直到遇到满二叉数为止,然后用2^树深度-1计算满二叉树的节点个数。
代码如下:
int countNodes(TreeNode* root) {
if (!root) return 0;
int leftDepth = 0;
int rightDepth = 0;
TreeNode* curLeft = root->left;
TreeNode* curRight = root->right;
while (curLeft){
curLeft = curLeft->left;
leftDepth++;
}
while (curRight){
curRight = curRight->right;
rightDepth++;
}
if (leftDepth == rightDepth){
return (2 << leftDepth) - 1;
}
return countNodes(root->left) + countNodes(root->right) + 1;
}
时间复杂度:O(logn*logn),空间复杂度:O(logn)。
总结
二叉树总要涉及到各种遍历的方式,采取正确的遍历方式和终止条件是无比重要的。