目录
第一题 二叉树的高度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL){
return 0;
}
int left_hign=maxDepth(root->left);
int right_hign=maxDepth(root->right);
return left_hign>right_hign?left_hign+1 : right_hign+1;
}
};
第二题 计算树的节点个数
给你一棵完全二叉树的根节点root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==nullptr){
return 0;
}
return countNodes(root->left)+countNodes(root->right)+1;
}
};
第三题 单值二叉树
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true
;否则返回 false
。
class Solution {
public:
bool isUnivalTree(TreeNode* root) {
if(root==nullptr){
return true;
}
if(root->left&&root->val!=root->left->val){
return false;
}
if(root->right&&root->val!=root->right->val){
return false;
}
// else{
// return true;//写了这个的话就没办法往下递归了
// }
return isUnivalTree(root->left)&&isUnivalTree(root->right);
}
};
第四题 相同的树
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==nullptr&&q==nullptr){//都为空
return true;
}
else if(p==nullptr||q==nullptr){//一空一有
return false;
}
else if(p->val!=q->val){//都有
return false;
}
else { //如果当前节点没有问题,那么向下递归
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
}
};
第五题 二叉树的前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
preoreder(ret,root);
return ret;
}
void preoreder(vector<int> &ret,TreeNode* cur){
if(cur==nullptr){
return ;
}
else{
ret.push_back(cur->val);
}
preoreder(ret,cur->left);
preoreder(ret,cur->right);
}
};
第六题 翻转二叉树
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
invert(root);
return root;
}
void invert(TreeNode* cur){
if(cur==nullptr){//注意是两个等于号
return ;
}
TreeNode* tmp=cur->right;
cur->right=cur->left;
cur->left=tmp;
invert(cur->right);
invert(cur->left);
}
};
一个小优化
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
invert(root);
return root;
}
void invert(TreeNode*& cur){//尽量使用传引用
if(cur==nullptr){
return ;
}
TreeNode* tmp=cur->right;
cur->right=cur->left;
cur->left=tmp;
invert(cur->right);
invert(cur->left);
}
};
第七题 对称二叉树
递归法
我们可以实现这样一个递归函数,通过「同步移动」两个指针的方法来遍历这棵树, p指针和 指针一开始都指向这棵树的根,随后 p 右移时,q 左移,p左移时,q右移。每次检查当前 p 和 q 节点的值是否相等,如果相等再判断左右子树是否对称。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root==nullptr){
return true;
}
return isSym(root,root);
}
bool isSym(TreeNode*& left,TreeNode*& right){
if (!left && !right) return true;//我要让空进去,所以对两个空连续取反
if (!left || !right) return false;//一空一非空
return left->val == right->val && isSym(left->left, right->right) && isSym(left->right, right->left);
}
};
迭代法
前面我们用递归的方法实现了对称性的判断,那么如何用迭代的方法实现呢?首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。
class Solution {
public:
bool check(TreeNode *u, TreeNode *v) {
queue <TreeNode*> q;
q.push(u); q.push(v);
while (!q.empty()) {
u = q.front(); q.pop();
v = q.front(); q.pop();
if (!u && !v) continue;
if ((!u || !v) || (u->val != v->val)) return false;
q.push(u->left);
q.push(v->right);
q.push(u->right);
q.push(v->left);
}
return true;
}
bool isSymmetric(TreeNode* root) {
return check(root, root);
}
};
第八题 另一颗树的子树
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root==nullptr){
return false;
}
return isSametree(root,subRoot)||isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
//检查当前节点然后按任意序列遍历子树
}
bool isSametree(TreeNode* p,TreeNode* q){
if(!p&&!q){
return true;
}
if(!p||!q){
return false;
}
return p->val==q->val&&isSametree(p->left,q->left)&&isSametree(p->right,q->right);
}
};
第九题 创建二叉树并且遍历它
1.c语言写法
#include <stdio.h>
#include <malloc.h>
typedef struct BTNode
{
char _data;
struct BTNode* _left;
struct BTNode* _right;
}BTNode;
//中序遍历
void Inorder(BTNode* root)
{
if(root)
{
Inorder(root->_left);
printf("%c ", root->_data);
Inorder(root->_right);
}
}
BTNode* CreatBTree(char* str, int* pi)
{
if(str[*pi]!= '#')
{
//当前节点非空,则创建当前节点
BTNode*root=(BTNode*)malloc(sizeof(BTNode));
root->_data = str[*pi];
//字符位置向后移动一个位置
++(*pi);
//创建左子树
root->_left=CreatBTree(str,pi);
//字符位置向后移动一个位置
++(*pi);
//创建右子树
root->_right=CreatBTree(str,pi);
return root;
}
else
return NULL; //如果是空节点,则返回NULL
}
int main()
{
char str[101];
int i = 0;
//读入字符串
scanf("%s", str);
//创建二叉树
BTNode* root = CreatBTree(str, &i);
//中序打印二叉树
Inorder(root);
printf("\n");
return 0;
}
2.c++写法
#include<string>
using namespace std;
class BTNode {
public:
char value;//节点值
BTNode *l;//左孩子
BTNode *r;//右孩子
BTNode() {
value = '0';
l = NULL;
r = NULL;
}
~BTNode() {
this->l = NULL; this->r = NULL;
delete(this);
}
};
//利用先序遍历构建二叉树
void initBT(BTNode * root) {
//访问结点值
//访问左子树
char temp = cin.get();
if (temp == '#') {
root->l = NULL;
}
else {
BTNode *btn1 = new BTNode();
btn1->value = temp;
root->l = btn1;
initBT(root->l);//接着对左子树先序遍历
}
//访问右子树
temp = cin.get();
if (temp == '#') {
root->r= NULL;
}
else {
BTNode *btn2 = new BTNode();
btn2->value = temp;
root->r = btn2;
initBT(root->r);//接着对右子树先序遍历
}
}
//中序遍历并进行输出
void inOrderTravel(BTNode * root) {
if (root == NULL)return;//空结点,直接返回
//访问左子树
if (root->l != NULL) {
inOrderTravel(root->l);//访问左子树
}
//访问结点值
cout << root->value << " ";
//访问右子树
if (root->r != NULL) {
inOrderTravel(root->r);//访问右子树
}
}
int main() {
char c = cin.get();
BTNode *root = new BTNode();
root->value = c;
initBT(root);//构建二叉树
inOrderTravel(root);//中序遍历,并且输出中序序列
cout << endl;
return 0;
}
第十题 平衡二叉树
1.自顶向上
class Solution {
public:
bool isBalanced(TreeNode* root) {
return isbal(root);
}
bool isbal(TreeNode*& cur){
if(cur==nullptr){
return true;
}
if(abs(tree_high(cur->left)-tree_high(cur->right))<2){
return true&&isbal(cur->left)&&isbal(cur->right);
}
else{
return false;
}
}
int tree_high(TreeNode*& cur){
if(cur==nullptr){
return 0;
}
int left_high=tree_high(cur->left);
int right_high=tree_high(cur->right);
return left_high>right_high?left_high+1:right_high+1;
}
};
这个写法更抽象也更简洁
return max(height(root->left), height(root->right)) + 1;
由于是自顶向下递归,因此对于同一个节点,函数
height会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个节点,函数
height 只会被调用一次。
2.自底向上(优化)
自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整数),否则返回 −1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。
class Solution {
public:
int height(TreeNode* root) {
if (root == NULL) {
return 0;
}
int leftHeight = height(root->left);
int rightHeight = height(root->right);
if (leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1) {
return -1;
} else {
return max(leftHeight, rightHeight) + 1;
}
}
bool isBalanced(TreeNode* root) {
return height(root) >= 0;
}
};