本节我们将汇总一些 LeetCode 有关二叉树的题。
鉴于 LeetCode 测试的方式是系统给出样例并自动测试的。
我们在本地的话,可以手动输入样例,返回测试结果。
首先我们建立二叉树的节点。为了能手动输入数据,我们使用层序遍历的方式创建树,使用层序遍历查看树是否满足要求,之后的工作和 LeetCode 就类似了。
所有代码的地址位于 github 上,后续将持续更新。
基本的程序框架
只要能手动输入树的信息并保存下来即可,这里我们使用了层序遍历的方式创建树。为了更好理解,我们使用层序遍历的方式查看树。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef string ElemType;
//定义树的节点
typedef struct BinaryNode{
//节点
ElemType val;
//左子树
BinaryNode* left;
//右子树
BinaryNode* right;
BinaryNode(ElemType x) : val(x),left(NULL),right(NULL){}
}BinaryNode,*BiTree;
//二叉树
//层序遍历创建二叉树
/*
先将根节点入队,当队列不为空时,循环执行以下操作:
输入左子树的值,不为空,将其入队
输入右子树的值,不为空,将其入队
*/
BiTree levelCreate(){
ElemType value;
BiTree root;
queue<BiTree> q;
cin>>value;
if(value == "#"){
return NULL;
}else{
root = new BinaryNode(value);
q.push(root);
}
while(!q.empty()){
BiTree p = q.front();
q.pop();
cin>>value;
if(value == "#"){
p->left = NULL;
}else{
p->left = new BinaryNode(value);
q.push(p->left);
}
cin>>value;
if(value == "#"){
p->right = NULL;
}else{
p->right = new BinaryNode(value);
q.push(p->right);
}
}
return root;
}
//实现层次遍历
void levelOrder(BiTree root){
queue<BiTree> q;
q.push(root);
while(!q.empty()){
//每层的节点
int num_level = q.size();
while(num_level--){
BiTree node = q.front();
q.pop();
cout<<node->val<<" ";
if(node->left){
q.push(node->left);
}
if(node->right){
q.push(node->right);
}
}
}
}
// 摧毁树
void destroy(BiTree root){
if(root != NULL){
destroy(root->left);
destroy(root->right);
free(root);
}
}
测试代码:
int main(){
BiTree tree;
/* 层序遍历
1 2 3 4 5 6 7 # # # # # # # #
*/
tree = levelCreate();
levelOrder(tree);
return 0;
}
测试一下:
1 2 3 4 5 6 7 # # # # # # # #
1 2 3 4 5 6 7
正确。
接下来看一些例题,所有题均来自于leetcode,我们在这个框架的基础进行解题。方法不唯一。
相同的树
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

这个题比较简单,如果两个节点为空,返回 true;在两个节点都不为空的情况下,数据域相同,说明该节点相同,继续递归其左子树后右子树;除此之外,均为 false。
程序如下:
// 100 相同的树
bool isSameTree(BiTree tree1,BiTree tree2){
if(tree1 == NULL && tree2 == NULL){
return true;
}
if(tree1 != NULL && tree2 != NULL && tree1->val == tree2->val){
return isSameTree(tree1->left,tree2->left) && isSameTree(tree1->right,tree2->right);
}else{
return false;
}
}
测试代码:
int main(){
BiTree tree1 = levelCreate();
BiTree tree2 = levelCreate();
cout<<isSameTree(tree1,tree2)<<endl;
return 0;
}
来测试一下
1 2 3 # # # #
1 2 3 # # # #
1
1 2 # # #
1 # 2 # #
0
1 2 1 # # # #
1 1 2 # # # #
0
下一题
对称二叉树
给定一个二叉树,检查它是否是镜像对称的。

使用递归回溯的方式,比较左子树和右子树。
代码如下:
// 101 对称二叉树
bool isSymmetric_helper(BiTree tree_left,BiTree tree_right){
if(tree_left == NULL && tree_right == NULL){
return true;
}
if((tree_left == NULL || tree_right == NULL)||(tree_left->val != tree_right->val)){
return false;
}
return isSymmetric_helper(tree_left->right,tree_right->left) && isSymmetric_helper(tree_left->left,tree_right->right);
}
bool isSymmetric(BiTree root){
if(root == NULL){
return true;
}
return isSymmetric_helper(root->left,root->right);
}
测试代码:
int main(){
BiTree tree = levelCreate();
cout<<isSymmetric(tree)<<endl;
return 0;
}
测试一下:
1 2 2 3 4 4 3 # # # # # # # #
1
1 2 2 # 3 # 3 # # # #
0
二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

节点为空时,返回 0 ;否则,递归的左子树,右子树,返回最大值并加一。
代码如下:
// 104 二叉树的最大深度
int maxDepth(BiTree root){
if(root == NULL){
return 0;
}
int left_ = maxDepth(root->left);
int right_ = maxDepth(root->right);
return max(left_,right_) + 1;
}
测试代码:
int main(){
BiTree tree = levelCreate();
cout<<maxDepth(tree)<<endl;
return 0;
}
结果如下:
3 9 20 # # 15 7 # # # #
3
二叉树的层序遍历 II
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

不同于层序遍历,此题需要递归。
代码如下:
// 107 二叉树的层次遍历 II
void levelOrderBottom_helper(vector<vector<ElemType>>& res,BiTree root,int level){
if(root == NULL){
return ;
}
if(level == res.size()){
res.push_back({});
}
res[level].push_back(root->val);
if(root->left){
levelOrderBottom_helper(res,root->left,level+1);
}
if(root->right){
levelOrderBottom_helper(res,root->right,level+1);
}
}
vector<vector<ElemType>> levelOrderBottom(BiTree root){
vector<vector<ElemType>> res;
levelOrderBottom_helper(res,root,0);
reverse(res.begin(),res.end());
return res;
}
测试代码:
int main(){
BiTree tree = levelCreate();
vector<vector<ElemType>> res = levelOrderBottom(tree);
for(auto r : res){
for(auto _r : r){
cout<<_r<<" ";
}
cout<<endl;
}
return 0;
}
测试一下:
3 9 20 # # 15 7 # # # #
15 7
9 20
3
将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

代码如下:
// 108 将有序数组转换为二叉搜索树
BiTree sortedArrayToBST_helper(vector<ElemType>& nums,int start_,int end_){
if(start_ > end_){
return nullptr;
}
int mid = start_ + (end_ - start_)/2;
BiTree point = new BinaryNode(nums[mid]);
point->left = sortedArrayToBST_helper(nums,start_,mid-1);
point->right = sortedArrayToBST_helper(nums,mid+1,end_);
return point;
}
BiTree sortedArrayToBST(vector<ElemType>& nums){
if(nums.size() == 0){
return nullptr;
}
return sortedArrayToBST_helper(nums,0,nums.size()-1);
}
测试代码:
int main(){
vector<ElemType> nums{"-10","-3","0","5","9"};
BiTree tree = sortedArrayToBST(nums);
levelOrder(tree);
return 0;
}
结果:
0 -10 5 -3 9
平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

代码如下:
// 110 平衡二叉树
int isBalanced_helper(BiTree root){
if(root == NULL){
return 1;
}else{
return max(isBalanced_helper(root->left),isBalanced_helper(root->right)) + 1;
}
}
bool isBalanced(BiTree root){
if(root == NULL){
return true;
}else{
int ans = abs(isBalanced_helper(root->left) - isBalanced_helper(root->right));
return (ans <= 1) && isBalanced(root->left) && isBalanced(root->right);
}
}
测试代码:
int main(){
BiTree tree = levelCreate();
cout<<isBalanced(tree);
return 0;
}
测试结果:
3 9 20 # # 15 7 # # # #
1
1
2 2
3 3 # #
4 4 # #
# # # #
0
二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。

代码如下:
// 111 二叉树的最小深度
int minDepth(BiTree root){
if(root == NULL){
return 0;
}
int level = 1;
if(root->left == NULL && root->right == NULL){
return level;
}
if(root->left == NULL){
return level + minDepth(root->right);
}
if(root->right == NULL){
return level + minDepth(root->left);
}
return level + min(minDepth(root->left),minDepth(root->right));
}
测试代码:
int main(){
BiTree tree = levelCreate();
cout<<minDepth(tree);
return 0;
}
测试结果:
3 9 20 # # 15 7 # # # #
2
路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。

代码如下:
// 112 路径总和
bool hasPathSum(BiTree root,int sum){
if(root == NULL){
return false;
}
if(root->left == NULL && root->right == NULL && sum == stoi(root->val)){
return true;
}
if(root->left != NULL && hasPathSum(root->left,sum - stoi(root->val))){
return true;
}
if(root->right != NULL && hasPathSum(root->right,sum - stoi(root->val))){
return true;
}
return false;
}
测试代码:
int main(){
BiTree tree = levelCreate();
int sum;
cin>>sum;
cout<<hasPathSum(tree,sum)<<endl;
return 0;
}
结果为:
5
4 8
11 # 13 4
7 2 # 1 # #
# # # # # #
22
1
全部代码见 github ,main.cpp 中不带测试程序。
本节内容到此结束,之后将继续更新。