参考博客
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
思路 :利用递归,深度优先搜索,调用递归函数看结点的左子树和右子树中哪个更深,直到遇到叶子结点
官方题解
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
//深度优先搜索
if(!root)
return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
//中序遍历得到的序列
vector<int>treeNum;
//对二叉树进行中序遍历
InOrderTraverse(root,treeNum);
//判断是否升序
for(int i=1;i<treeNum.size();i++)
{
if(treeNum[i]<=treeNum[i-1])
return false;
}
return true;
}
//中序遍历(左根右)
void InOrderTraverse(TreeNode * root,vector<int>&arr)
{
if(root)
{
//递归调用
InOrderTraverse(root->left,arr);
arr.push_back(root->val);
InOrderTraverse(root->right,arr);
}
}
};
解法二 在中序遍历过程中直接判断是否有序(来自题解【代码随想录】)
long long
的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int
最小值,所以定义为long long
的类型,初始化为long long
最小值。true
maxVal
,一旦发现maxVal >= root->val
,就返回false
,注意元素相同时候也要返回false。代码
class Solution {
public:
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
bool isValidBST(TreeNode* root) {
if (root == NULL) return true;
bool left = isValidBST(root->left);
// 中序遍历,验证遍历的元素是不是从小到大
if (maxVal < root->val) maxVal = root->val;
else return false;
bool right = isValidBST(root->right);
return left && right;
}
};
上图中下面的那个示例,说明即使数字是对称的,但是所在的位置不是镜像对称的也不是对称二叉树,所以不能只考虑比较结点值,而应注意是否为对称位,因此不能验证通过中序遍历得到的数组是否是回文串来判断是否为对称二叉树。
思路: (官方题解)
check
,通过同步移动两个指针的方法来遍历这棵树代码
class Solution {
public:
bool check(TreeNode *p, TreeNode *q) {
//都为空时返回true
if (!p && !q) return true;
//只有一个为空时,说明不对称,返回false
if (!p || !q) return false;
//比较当前结点值,以及利用递归遍历整棵树
return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
}
bool isSymmetric(TreeNode* root) {
return check(root, root);
}
};
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
思路:
size
size
个元素进行拓展(将结点的左子树和右子树压到队尾,如果有的话),然后进入下一层的迭代size
个元素是属于同一层的,将这些数用一维数组存起来,每层拓展完成后将这个数组加到二维数组中去。代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if(!root) return{};
vector<vector<int>>result;
vector<int>tmp;
TreeNode* node;
//利用队列
queue<TreeNode*>que;
//放入根结点
que.push(root);
while(!que.empty())
{
//求出每层的节点数
int queSize=que.size();
//展开que中queSize个元素(属于同一层的元素)
for(int i=0;i<queSize;i++)
{
//取出队列中的第一个元素
node=que.front();
//然后将它弹出
que.pop();
//将节点值插入数组
tmp.push_back(node->val);
//展开当前节点的坐左子树和右子树(如果有的话)
//将左孩子和右孩子节点压到队列尾部
if(node->left)
que.push(node->left);
if(node->right)
que.push(node->right);
}
//向结果数组压入二叉树每层的节点值
result.push_back(tmp);
tmp.clear();
}
return result;
}
};
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
思路:
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums)
{
//借助一个递归函数来实现
return helper(nums,0,nums.size()-1);
}
TreeNode * helper(vector<int>& nums,int left,int right)
{
//终止条件
if(left>right)
return nullptr;
//中序序列构造搜索二叉树
//每次取数组中点作为根节点
int mid=(left+right)/2;
//递归调用,创建一个新节点,左子树为数组左半段,右子树为数组右半段
TreeNode* root=new TreeNode(nums[mid],helper(nums,left,mid-1),helper(nums,mid+1,right));
//返回根节点地址(开辟在堆区)
return root;
}
};
在一个 n * m
的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:
matrix
有非常特殊的排列方式,从上到下递增,从左到右递增。15
左边的元素更小,右边元素更大;18
上边元素更小,右边元素更大。18
那个位置(坐标原点)开始搜索,假如小于目标target=5
,则将搜索位置向右移动,大于则向上移动bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
//注意异常判断
if(matrix.empty())
return 0;
int m=matrix.size(),n=matrix[0].size();
//从最左下开始搜索
int i=m-1,j=0;
while(i>=0&&j<n)
{
if(target<matrix[i][j])
i--; //向上
else if(target>matrix[i][j])
j++; //向右
else
return true;
}
return false;
}
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
//递归构建,后面四个参数分别为前序和中序遍历的左右界
TreeNode* mybuild(vector<int>& preorder, vector<int>& inorder,unordered_map<int,int>& index,int pre_left,int pre_right,int in_left,int in_right)
{
//不要忘了递归终止条件!!!
if(pre_left>pre_right)
return NULL;
//先序遍历中的根节点
int pre_root=preorder[pre_left];
//构建根节点
TreeNode* root=new TreeNode(pre_root);
//根据先序根节点找中序遍历根节点
int in_root=index[pre_root];
//根据中序根节点计算左子树长度
int left_size=in_root-in_left;
//构建左子树,最后四个参数分别为先序和中序遍历中的左子树部分
root->left=mybuild(preorder,inorder,index,pre_left+1,pre_left+left_size,in_left,in_root-1);
//构建右子树,后四个参数分别为先序和中序遍历中的右子树部分
root->right=mybuild(preorder,inorder,index,pre_left+left_size+1,pre_right,in_root+1,in_right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n=preorder.size();
unordered_map<int,int>index;
for(int i=0;i<inorder.size();i++)
{
index[inorder[i]]=i;
}
TreeNode* head=mybuild(preorder,inorder,index,0,n-1,0,n-1);
return head;
}
};
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
思路:
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
//如果两节点均非空
if(root1!=NULL&&root2!=NULL)
{
int m_val=root1->val+root2->val;
//构造一个新节点,值为重复节点的值的和
TreeNode* newRoot=new TreeNode(m_val);
//递归构造左右子树
newRoot->left=mergeTrees(root1->left,root2->left);
newRoot->right=mergeTrees(root1->right,root2->right);
return newRoot;
}
//有一个为空
else if(root1==NULL)
{
return root2;
}
else if(root2==NULL)
{
return root1;
}
//都为空
return NULL;
}
};
复杂度
时间O(min(m,n))
,m
和n
分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会对该节点进行显性合并操作,因此被访问到的节点数不会超过较小的二叉树的节点数。空间O(min(m,n))
。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点(完全二叉树)。
填充它的每个next
指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next
指针设置为 NULL
。
初始状态下,所有 next
指针都被设置为NULL
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
解法一
class Solution {
public:
Node* connect(Node* root) {
//广度优先搜索,层次遍历
queue<Node*>Q;
int n=0;
if(root==NULL)
return root;
Q.push(root);
while(!Q.empty())
{
int size=Q.size();
for(int i=0;i<size;i++)
{
Node* tmp=Q.front();
Q.pop();
if(i!=size-1)
tmp->next=Q.front();
if(tmp->left!=NULL)
Q.push(tmp->left);
if(tmp->right!=NULL)
Q.push(tmp->right);
}
n++;
}
return root;
}
};
解法二
next 指针
,迭代,思路见官方题解解法三