110.平衡二叉树
思路:
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
- 因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
递归
class Solution { public: // 返回以该节点为根节点的二叉树的高度,如果不是平衡二叉树了则返回-1 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; } };
迭代法:
在104.二叉树的最大深度 (opens new window)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
本题的迭代方式可以先定义一个函数,专门用来求高度。
这个函数通过栈模拟的后序遍历找每一个节点的高度(其实是通过求传入节点为根节点的最大深度来求的高度)
class Solution { private: int getDepth(TreeNode* cur) { stack<TreeNode*> st; if (cur != NULL) st.push(cur); int depth = 0; // 记录深度 int result = 0; while (!st.empty()) { TreeNode* node = st.top(); if (node != NULL) { st.pop(); st.push(node); // 中 st.push(NULL); depth++; if (node->right) st.push(node->right); // 右 if (node->left) st.push(node->left); // 左 } else { st.pop(); node = st.top(); st.pop(); depth--; } result = result > depth ? result : depth; } return result; } public: bool isBalanced(TreeNode* root) { stack<TreeNode*> st; if (root == NULL) return true; st.push(root); while (!st.empty()) { TreeNode* node = st.top(); // 中 st.pop(); if (abs(getDepth(node->left) - getDepth(node->right)) > 1) { return false; } if (node->right) st.push(node->right); // 右(空节点不入栈) if (node->left) st.push(node->left); // 左(空节点不入栈) } return true; }
257. 二叉树的所有路径
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
class Solution { private: void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) { path.push_back(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中 // 这才到了叶子节点 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(); // 回溯 } } public: vector<string> binaryTreePaths(TreeNode* root) { vector<string> result; vector<int> path; if (root == NULL) return result; traversal(root, path, result); return result; } };
迭代:
class Solution { private: void traversal(TreeNode* cur, string path, vector<string>& result) { path += to_string(cur->val); // 中,中为什么写在这里,因为最后一个节点也要加入到path中 if (cur->left == NULL && cur->right == NULL) { result.push_back(path); return; } if (cur->left) { path += "->"; traversal(cur->left, path, result); // 左 path.pop_back(); // 回溯 '>' path.pop_back(); // 回溯 '-' } if (cur->right) { path += "->"; traversal(cur->right, path, result); // 右 path.pop_back(); // 回溯'>' path.pop_back(); // 回溯 '-' } } public: vector<string> binaryTreePaths(TreeNode* root) { vector<string> result; string path; if (root == NULL) return result; traversal(root, path, result); return result; } };
404.左叶子之和
首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点
class Solution { public: int sumOfLeftLeaves(TreeNode* root) { if (root == NULL) return 0; if (root->left == NULL && root->right== 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); // 右 int sum = leftValue + rightValue; // 中 return sum; } };