第226题 翻转二叉树
解题思路:采用后续遍历,因为后续是左右根,即可从最下面开始,自下而上的交换左右子树。
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
//采用后序遍历
//判断树不为空
if(root == nullptr)
return root;
TreeNode* p = root;
//开始迭代求解
invertTree(p->left);
invertTree(p->right);
swap(p->left,p->right);
return root;
}
};
第101题 对称二叉树
解题思路:如何判断一个二叉树轴对称(镜像)呢?其实是相当于把左右子树看成两棵独立的树,对这两棵独立的树,自下而上的开始对比,要对两棵树进行后序遍历,但是后序遍历的顺序有区别,一棵是左右根,一棵是右左根,二者相等才能说明对称
class Solution {
public:
//递归法
bool comTrees(TreeNode* LTree,TreeNode* RTree)
{
//都是空结点
if(LTree == nullptr && RTree == nullptr)
return true;
//一空一不空
else if(LTree != nullptr && RTree == nullptr)
return false;
else if(LTree == nullptr && RTree != nullptr)
return false;
//都不空
else if(LTree->val != RTree->val)
return false;
//都相等继续往下判断
else
return comTrees(LTree->left,RTree->right) && comTrees(LTree->right, RTree->left);;
}
//迭代法
bool isSymmetric(TreeNode* root){
//用栈存储“两棵树”的左右结点,然后出栈比较
stack<TreeNode*> st;
if(root == nullptr)
return true;
//先把根节点的左右子树压入栈
st.push(root->left);
st.push(root->right);
while(!st.empty())
{
//出栈两个元素进行比较
TreeNode* node_1=st.top();
st.pop();
TreeNode* node_2=st.top();
st.pop();
//若都是空结点,跳过本次循环开始下一次
if(node_1==nullptr && node_2==nullptr)
continue;
if((!node_1 || !node_2) || node_1->val != node_2->val)
return false;
//若当前处于对称状态,继续向下判断
st.push(node_1->left);
st.push(node_2->right);
st.push(node_1->right);
st.push(node_2->left);
}
return true;
}
bool isSymmetric(TreeNode* root) {
//如何判断一个二叉树轴对称(镜像)呢?其实是相当于把左右子树看成两棵独立的树
//对这两棵独立的树,自下而上的开始对比,要对两棵树进行后序遍历
//但是后序遍历的顺序有区别,一棵是左右根,一棵是右左根,二者相等才能说明对称
if(root == nullptr)
return true;
TreeNode* root_1 = root->left;
TreeNode* root_2 = root->right;
return comTrees(root_1,root_2);
}
};
第100题 相同的树
解题思路:同101题
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
//迭代法
if(p==nullptr && q==nullptr)
return true;
if(p==nullptr || q==nullptr)
return false;
stack<TreeNode*> st;
st.push(p);
st.push(q);
while(!st.empty())
{
TreeNode* node_1 = st.top();
st.pop();
TreeNode* node_2 = st.top();
st.pop();
if(node_1==nullptr && node_2==nullptr)
continue;
if((!node_1 || !node_2)||(node_1->val != node_2->val))
return false;
st.push(node_1->left);
st.push(node_2->left);
st.push(node_1->right);
st.push(node_2->right);
}
return true;
}
};
第572题 另一棵树的子树
解题思路:同样是判断是否有相等子树,这里在遍历根树是借用了栈
class Solution {
public:
//递归法求相同树
bool isSametree(TreeNode* p,TreeNode* q)
{
if(p==nullptr && q==nullptr)//p,q都空
return true;
else if(p==nullptr || q==nullptr)//p或q其中一个不为空
return false;
else if(p->val != q->val)//p和q都不空
return false;
else
return isSametree(p->left,q->left) && isSametree(p->right,q->right);
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
//前序遍历root树
stack<TreeNode*> st;
st.push(root);
while(!st.empty())
{
TreeNode* p = st.top();
st.pop();
if(p->val == subRoot->val)
{
bool res = isSametree(p,subRoot);
//若当前结点相等但不是相等树,继续往下找找
if(res == true)
return res;
}
if (p->right!=nullptr) st.push(p->right);
if (p->left!=nullptr) st.push(p->left);
}
return false;
}
};
第104题 二叉树最大深度
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr)
return 0;
//前序遍历:自上而下求深度
//后序遍历:自下而上求高度(后序遍历也可以求深度)
//分别遍历左右子树,谁深就要谁
int lefthigh = 1 + maxDepth(root->left);
int righthigh =1 + maxDepth(root->right) ;
int res = lefthigh>righthigh?lefthigh:righthigh;
return res;
}
};
第110题 平衡二叉树
解题思路:本质上还是求树的高度,若当前根节点左右子树高度差值大于1,就不是平衡二叉树。
class Solution {
public:
int getDeepth(TreeNode* root)
{
if(root==nullptr)
return 0;
int Ldeep = getDeepth(root->left) +1;
int Rdeep = getDeepth(root->right) + 1;
return Ldeep>Rdeep?Ldeep:Rdeep;
}
bool isBalanced(TreeNode* root) {
//递归解法
//以根节点为起始,若当前左右子树高度差值大于1,就不是二叉树
if(root==nullptr)
return true;
int leftDeep = 0;
int rightDeep = 0;
leftDeep = getDeepth(root->left);
rightDeep = getDeepth(root->right);
if(abs(leftDeep-rightDeep)>1)
return false;
else
return isBalanced(root->left) && isBalanced(root->right);
}
};
第111题 二叉树的最小深度
class Solution {
public:
int minDepth(TreeNode* root) {
//采用后序遍历,找最小深度
if(root == nullptr)
return 0;
if(root->left != nullptr && root->right != nullptr)
{
int lefthigh = minDepth(root->left) + 1;
int righthigh = minDepth(root->right) + 1;
return lefthigh<righthigh?lefthigh:righthigh;
}
else if(root->left == nullptr && root->right != nullptr)
return 1 + minDepth(root->right);
else if(root->left != nullptr && root->right == nullptr)
return 1 + minDepth(root->left);
else
return 1;
}
};
第222题 完全二叉树的节点个数
解题思路:一棵完全二叉树可以看成许多个子满二叉树组成的,因此,若当前二叉树不是满二叉树,则递归找下面的满二叉树(单个结点也是一个满二叉树),满二叉树的结点数为2^deep - 1,若当前不是满二叉树,分别递归左右子树,在左右递归返回时,还要加上当前的根节点。具体思路如下:
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == nullptr)
return 0;
//分别求左侧右侧深度
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDeep = 0;
int rightDeep = 0;
//开始求左子树
while(left!=nullptr)
{
left = left->left;
leftDeep++;
}
//再求右子树
while(right!=nullptr)
{
right = right->right;
rightDeep++;
}
//若左右子树深度相等,则说明当前子树就是一个完全二叉树
if(leftDeep == rightDeep)
return pow(2,leftDeep+1) - 1;
//若左右子树深度不等,说明当前子树不是一个完全二叉树,继续向下找完全二叉树
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
第257题 二叉树所有路径
解题思路:首先我们要先序遍历把路径记录下来,当走到第一条路径结尾时,需要回溯,回退到当前结点的根节点,然后进入另一个路径。这里使用了回溯思想。
class Solution {
public:
void PathTravel(TreeNode* root,vector<int>& path,vector<string>& res)
{
//因为最先需要存储的是根节点,所以需要先序遍历
path.push_back(root->val);
//若当前结点是叶子节点,递归出口
if(root->left==nullptr && root->right==nullptr)
{
//"打印当前路径",最后一个结点先不打印
string sp;
int i;
for(i = 0;i<path.size()-1;i++)
{
//字符串直接相加就是拼接
sp += to_string(path[i]);//to_string(int)是将int类型转换成字符串类型
sp += "->";//一个数字后面跟着一个“->”
}
//最后一个结点单独加
sp += to_string(path[i]);
//将当前路径存入结果中
res.push_back(sp);
return;
}
//若还没有到达叶子节点,继续递归
if(root->left)
{
PathTravel(root->left,path,res);
path.pop_back();//当前左子树遍历完,把左子树弹出,要开始遍历右子树,这就是回溯
}
if(root->right)
{
PathTravel(root->right,path,res);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
//递归加回溯
//定义存储结果的容器
vector<string> res;
//存储当前路径
vector<int> path;
if(root==nullptr)
return res;
//开始递归遍历
PathTravel(root,path,res);
return res;
}
};
第404题 左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。
解题思路:后序遍历,关键在于如何确定左叶子。
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
//后序遍历,只找左孩子
if (root == nullptr)
return 0;
//只有一个结点,也返回0
if (root->left == nullptr && root->right == nullptr)
return 0;
int leftnode = sumOfLeftLeaves(root->left);
//如何判断当前结点有左叶子?
//该结点的左孩子不为空,并且这个左孩子的左右孩子都是空
if (root->left && !root->left->left && !root->left->right)
leftnode = root->left->val;
//找完左子树再找右子树
int right_leftnode = sumOfLeftLeaves(root->right);
return leftnode+right_leftnode;
}
};
第513题 找树左下角的值
解题思路:层序遍历,每次遍历从右往左遍历,这样遍历到的最后一个结点就是最左结点
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> qe;
TreeNode* p = root;
qe.push(p);
vector<int> res;
while(!qe.empty())
{
int num = qe.size();
for(int i = 0;i<num;i++)
{
p = qe.front();
res.push_back(p->val);
qe.pop();
if(p->right) qe.push(p->right);
if(p->left) qe.push(p->left);
}
}
return res.back();
}
};
第112题 路径总和
解题思路:求和不好做,可以转换成找叶子节点是否等于“目标值-遍历过结点和”,若相等,即返回true。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr)
return false;
//当前是叶子结点
if(root->left == nullptr && root->right==nullptr)
{
if(targetSum == root->val)
return true;
else
return false;
}
//若不是叶子节点,向下迭代找叶子节点
//注意此处用或运算,即不管是左子树还是右子树,找到即可
return (hasPathSum(root->left,targetSum-root->val) || hasPathSum(root->right,targetSum-root->val));
}
};
第106题 从中序与后序遍历构造二叉树
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(postorder.size() == 0) return NULL;
//先看后续遍历确定根节点
int val = postorder.back();
TreeNode* root = new TreeNode(val);
//若当前是叶子结点,直接返回
if(postorder.size()==1) return root;
//根据根节点划分新的左右子树结点
//子树的中序遍历
//index指向的是根节点在中序数组中位置
int index;
for (index = 0;index<inorder.size();index++)
{
if (inorder[index] == val)
break;
}
vector<int> inorderleft(inorder.begin(), inorder.begin() + index);
vector<int> inorderright(inorder.begin() + index + 1, inorder.end());
//子树的后序遍历
vector<int> postleft(postorder.begin(), postorder.begin() + inorderleft.size());
vector<int> postright(postorder.begin() + inorderleft.size(), postorder.end() - 1);
//开始构建左右子树
root->left = buildTree(inorderleft, postleft);
root->right = buildTree(inorderright, postright);
return root;
}
};
第654题 最大二叉树
整体思路同上一题
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
if (nums.size() == 0)
return NULL;
//找最大值
int max_val = -1;
int max_index;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] > max_val)
{
max_val = nums[i];
max_index = i;
}
}
//新建节点
TreeNode* root = new TreeNode(max_val);
//若当前结点是叶子节点,构造完就退出
if (nums.size() == 1)
return root;
//根据叶子节点划分左右子树
vector<int> leftnum(nums.begin(), nums.begin() + max_index);
vector<int> rightnum(nums.begin() + max_index + 1, nums.end());
//开始构造左右子树
root->left = constructMaximumBinaryTree(leftnum);
root->right = constructMaximumBinaryTree(rightnum);
return root;
}
};
第617题 合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root2==nullptr)
return root1;
if(root1==nullptr)
return root2;
root1->val = root1->val+root2->val;
//开始构建左右子树
root1->left = mergeTrees(root1->left,root2->left);
root1->right = mergeTrees(root1->right,root2->right);
return root1;
}
};