0、NULL与nullptr的区别
在C语言中,NULL
通常被定义为:#define NULL ((void *)0)
。因为在C语言中把空指针赋给int
和char
指针的时候,发生了隐式类型转换,把void
指针转换成了相应类型的指针。
所以说NULL
实际上是一个空指针。在C++中,NULL
实际上是0
。因为C++中不能把void*
类型的指针隐式转换成其他类型的指针。
在C++11版本中特意引入了nullptr
这一新的关键字可以保证在任何情况下都代表空指针,以后用nullptr
替代NULL
,而NULL
就当做0
使用。
1、二叉树的前序遍历
问题描述
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,2,3]
代码实现
/**
* 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:
vector<int> ivec;
vector<int> preorderTraversal(TreeNode* root) {
if(root){
ivec.push_back(root->val);
if(root->left)
preorderTraversal(root->left);
if(root->right)
preorderTraversal(root->right);
}
return ivec;
}
};
运行截图
先序遍历的非递归算法
/**
* 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:
vector<int> preorderTraversal(TreeNode* root) {
if(root == NULL)
return {};
stack<TreeNode*> s;
vector<int> v;
TreeNode* p = root;
while(p or s.size()){
if(p){
v.push_back(p->val);
s.push(p);
p = p->left;
}
else{
p = s.top();
s.pop();
p = p->right;
}
}
return v;
}
};
运行截图
2、二叉树的中序遍历
问题描述
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
代码实现
/**
* 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:
vector<int> ivec;
vector<int> inorderTraversal(TreeNode* root) {
if(root){
if(root->left)
inorderTraversal(root->left);
ivec.push_back(root->val);
if(root->right)
inorderTraversal(root->right);
}
return ivec;
}
};
运行截图
二叉树中序遍历非递归算法
/**
* 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:
vector<int> inorderTraversal(TreeNode* root) {
if(root == NULL)
return {};
stack<TreeNode*> s;
vector<int> v;
TreeNode* p = root;
while(p or s.size()){
if(p){
s.push(p);
p = p->left;
}
else{
p = s.top();
s.pop();
v.push_back(p->val);
p = p->right;
}
}
return v;
}
};
运行截图
3、二叉树的后序遍历
问题描述
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
代码实现
/**
* 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:
vector<int> ivec;
vector<int> postorderTraversal(TreeNode* root) {
if(root){
if(root->left)
postorderTraversal(root->left);
if(root->right)
postorderTraversal(root->right);
ivec.push_back(root->val);
}
return ivec;
}
};
运行截图
二叉树后序遍历的非递归算法
/**
* 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:
vector<int> postorderTraversal(TreeNode* root) {
if(root == NULL)
return {};
stack<TreeNode*> s;
vector<int> v;
TreeNode *p = root, *pre = NULL;
while(p or s.size()){
if(p){
s.push(p);
p = p->left;
}
else{
p = s.top();
if(p->right && pre != p->right){
p = p->right;
}
else{
v.push_back(p->val);
s.pop();
pre = p;
p = NULL;
}
}
}
return v;
}
};
运行截图
4、二叉树的层序遍历
问题描述
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
解题思路
- 与以往的求二叉树的层序遍历略有不同。本题目的含义是将每层的二叉树结点存储到二维数组中。
- 就可以利用一个整型变量记录此时的队列中的元素个数,也就是某一层的元素个数。
- 当队头元素的孩子结点入队后,队头元素出队,记录元素个数的变量减一,直到该变量减为0,说明某一层的结点全部出队。
- 循环直到队列中没由元素为止。
代码实现
/**
* 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:
vector<vector<int>> levelOrder(TreeNode* root) {
if(root == NULL)
return {};
queue<TreeNode*> treeque; // 建立二叉树类型的队列
vector<vector<int>> allLevelVec; //存储层序遍历的数组
vector<int> eveLevelVec; // 存储每层的数组
treeque.push(root); // 根结点入队
while(treeque.size()){
int num = treeque.size(); // 记录当前队列中的元素个数
while(num){
eveLevelVec.push_back(treeque.front()->val); // 队头元素进入容器
num--; // 队列中元素个数减一
if(treeque.front()->left) // 队头元素左孩子不空 入队
treeque.push(treeque.front()->left);
if(treeque.front()->right) // 队头元素右孩子不空 入队
treeque.push(treeque.front()->right);
treeque.pop(); // 队头元素出队
}
allLevelVec.push_back(eveLevelVec);
eveLevelVec.clear();
}
return allLevelVec;
}
};
运行截图
本题相似题解——二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组.
示例 1:
输入:
3
/ \
9 20
/ \
15 7
输出: [3, 14.5, 11]
解释:
第0层的平均值是 3, 第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11].
代码实现
/**
* 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:
vector<double> averageOfLevels(TreeNode* root) {
vector<double> dvec;
queue<TreeNode*> q;
q.push(root);
while(q.size()){
int num1 = q.size(), num2 = q.size();
double d = 0;
while(num1){
d += q.front()->val;
num1--;
if(q.front()->left)
q.push(q.front()->left);
if(q.front()->right)
q.push(q.front()->right);
q.pop();
}
dvec.push_back(d/num2);
}
return dvec;
}
};
运行截图
5、平衡二叉树(包含求二叉树高度)
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 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:
int GetTreeDepth(TreeNode* root) { // 求二叉树的高度
if(root == NULL)
return 0;
int leftDepth = GetTreeDepth(root->left);
int rightDepth = GetTreeDepth(root->right);
return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
}
bool isBalanced(TreeNode* root) {
if(root == NULL)
return true;
bool leftBalance = true, rightBalance = true;
if(abs(GetTreeDepth(root->left) - GetTreeDepth(root->right)) > 1)
return false;
leftBalance = isBalanced(root->left);
rightBalance = isBalanced(root->right);
return leftBalance && rightBalance;
}
};
运行截图
6、对称二叉树
问题描述
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个[1,2,2,null,3,null,3]
则不是镜像对称的:
1
/ \
2 2
\ \
3 3
代码实现
/**
* 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:
bool isMirror(TreeNode* leftRoot, TreeNode* rightRoot){
if(leftRoot == NULL && rightRoot == NULL) //左右孩子为空 符合镜像条件
return true;
if(leftRoot == NULL || rightRoot == NULL)// 一个空 一个不空 显然不符合题意
return false;
return leftRoot->val == rightRoot->val // 左右孩子不空 结点值必须一致
&& isMirror(leftRoot->left, rightRoot->right)
&& isMirror(leftRoot->right, rightRoot->left);
}
bool isSymmetric(TreeNode* root) {
if(root == NULL)
return true;
return isMirror(root->left, root->right);
}
};
7、二叉树的最小深度
问题描述
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回它的最小深度2
。
解题思路
与求二叉树最大高度不同,求最小深度要考虑到单支树的最小高度不是1,而是有树枝的那边的高度。
代码实现
/**
* 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:
int minDepth(TreeNode* root) {
if(root == NULL)
return 0;
int minLeftDepth = minDepth(root->left);
int minrightDepth = minDepth(root->right);
if(root->left == NULL || root->right == NULL)
return minLeftDepth + minrightDepth + 1;
return min(minLeftDepth, minrightDepth) + 1;
}
};
运行截图
8、二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1
/ \
2 3
/ \
4 5
返回 3
, 它的长度是路径[4,2,1,3]
或者 [5,2,1,3]
。
注意: 两结点之间的路径长度是以它们之间边的数目表示。
解题思路
与求树高的算法类似,树高是根结点到叶子结点的最多结点数。本题是求任意两点的最大连接边的数目,是有一定区别的。
代码实现
/**
* 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:
int maxdiameter(TreeNode* root, int &num){
if(root == NULL)
return 0;
int l = maxdiameter(root->left, num);
int r = maxdiameter(root->right, num);
num = max(num, l + r);
return max(l ,r) + 1;
}
int diameterOfBinaryTree(TreeNode* root) {
int num = 0;
maxdiameter(root, num);
return num;
}
};
运行截图
9、相同的树
问题描述
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/ \
2 2
[1,2], [1,null,2]
输出: false
示例 3:
输入: 1 1
/ \ / \
2 1 1 2
[1,2,1], [1,1,2]
输出: 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:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p == NULL and q == NULL)
return true;
if(p == NULL or q == NULL)
return false;
return p->val == q->val and isSameTree(p->left, q->left) and isSameTree(p->right, q->right);
}
};
运行截图
10、路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回true
, 因为存在目标和为22
的根节点到叶子节点的路径 5->4->11->2
。
/**
* 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:
bool hasPathSum(TreeNode* root, int sum) {
if(root == NULL)
return false;
sum -= root->val;
if(root->left == NULL and root->right == NULL)
return sum == 0;
return hasPathSum(root->left, sum) or hasPathSum(root->right, sum);
}
};
运行截图
11、路径总和 II
问题描述
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
解题思路
以先序遍历思想为核心,没遍历一个结点均压入容器,遇到叶子结点后比较路径长度和sum值,记录所有符合题意的路径。
代码实现
/**
* 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:
bool isEqualSum(vector<int>& itmp, const int sum){
if(itmp.size() == 0)
return false;
return accumulate(itmp.begin(), itmp.end(), 0) == sum;
}
void findPathNode(TreeNode* root, vector<vector<int>> &ivec, vector<int>& itmp, int sum){
if(root){
itmp.push_back(root->val);
if(root->left == NULL and root->right == NULL and isEqualSum(itmp, sum))
ivec.push_back(itmp);
if(root->left)
findPathNode(root->left, ivec, itmp, sum);
if(root->right)
findPathNode(root->right, ivec, itmp, sum);
}
if(itmp.size())
itmp.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int sum) { // 主函数
if(root == NULL)
return {};
vector<vector<int>> ivec;
vector<int> itmp;
findPathNode(root, ivec, itmp, sum);
return ivec;
}
};
运行截图
12、二叉树的所有路径
问题描述
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:
1
/ \
2 3
\
5
输出:["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
。
解题思路
- 一定要注意被调用函数中的参数在什么情况下是引用传递,什么情况下是值传递。对于本题的写法,一定要用值传递。保证
string s
在每次迭代中的记忆性。 -
to_string()
函数将变量转化为string类型。
代码实现
/**
* 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:
void allpaths(TreeNode* root, vector<string> &svec, string s){
if(root){
s += to_string(root->val);
if(root->left == NULL and root->right == NULL)
svec.push_back(s);
else{
s += "->";
allpaths(root->left, svec, s);
allpaths(root->right, svec, s);
}
}
}
vector<string> binaryTreePaths(TreeNode* root) {
if(root == NULL)
return {};
vector<string> svec;
string s;
allpaths(root, svec, s);
return svec;
}
};
13、从前序与中序遍历序列构造二叉树
问题描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
代码实现
/**
* 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.empty() or inorder.empty())
return nullptr;
TreeNode* root = new TreeNode(preorder[0]);
int pos = 0;
for(; pos < preorder.size(); pos++)
if(preorder[0] == inorder[pos])
break;
vector<int> preorder_left(preorder.begin() + 1, preorder.begin() + pos + 1);
vector<int> preorder_right(preorder.begin() + pos + 1, preorder.end());
vector<int> inorder_left(inorder.begin(), inorder.begin() + pos);
vector<int> inorder_right(inorder.begin() + pos + 1, inorder.end());
root->left = buildTree(preorder_left, inorder_left);
root->right = buildTree(preorder_right, inorder_right);
return root;
}
};
运行截图
14、从中序与后序遍历序列构造二叉树
问题描述
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历inorder = [9,3,15,20,7]
后序遍历postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
代码实现
/**
* 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* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.empty() or postorder.empty())
return nullptr;
int n = postorder.size();
TreeNode* root = new TreeNode(postorder[n - 1]);
int pos = n - 1;
for(; pos >= 0; pos--)
if(inorder[pos] == postorder[n - 1])
break;
vector<int> inorder_left(inorder.begin(), inorder.begin() + pos + 1);
vector<int> inorder_right(inorder.begin() + pos + 1, inorder.end());
vector<int> postorder_left(postorder.begin(), postorder.begin() + pos);
vector<int> postorder_right(postorder.begin() + pos, postorder.end() - 1);
root->left = buildTree(inorder_left, postorder_left);
root->right = buildTree(inorder_right, postorder_right);
return root;
}
};
运行截图