关于二叉树的笔试面试问题很多,涉及到深度遍历和广度遍历,以及相关路径搜索,树的重构,以及与二叉搜索平衡树相关的基础问题。。
94. Binary Tree Inorder Traversal---考察二叉树中序遍历
题目描述:
Given a binary tree, return the inorder traversal of its nodes' values.
For example:
Given binary tree [1,null,2,3]
,
1 \ 2 / 3
return [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:
void InorderTraverseBinaryTree(TreeNode* root, vector<int> &out)
{
if(root == NULL)
return;
// 向左走
InorderTraverseBinaryTree(root->left, out);
// 访问当前节点
out.push_back(root->val);
// 向右走
InorderTraverseBinaryTree(root->right, out);
return;
}
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> out;
InorderTraverseBinaryTree(root, out);
return out;
}
};
98. Validate Binary Search Tree---利用中序遍历判断
问题描述:
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than the node's key.
- Both the left and right subtrees must also be binary search trees.
Example 1:
2 / \ 1 3Binary tree
[2,1,3]
, return true.
Example 2:
1 / \ 2 3Binary tree
[1,2,3]
, return false.
问题解析:
1. 此题想要判断一颗二叉树是否是二叉搜索树,也就是说,一个节点其左子树的所有节点值都必须小于它,右子树的节点值都必须大于它的值。
2. 考虑到二叉搜索树的中序遍历是一个递增序列,因此采用中序遍历的解法来做。
3. 比较易懂的解法是:设置一个辅助数组,将中序遍历二叉树的结果存在辅助数组中,最后检查数组的是否是递增来判断是否是二叉搜索树。如下代码1,或者可以取消辅助数组,总是和中序遍历上一个值来比较,直到遍历结束,入代码二。
代码如下1:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// 中序遍历二叉树
void InOrderTraverseBinaryTree(TreeNode* root, vector<int> &res)
{
if(root == NULL)
return;
InOrderTraverseBinaryTree(root->left, res);
res.push_back(root->val);
InOrderTraverseBinaryTree(root->right, res);
return;
}
class Solution
{
public:
// 判断是不是有效的二叉搜索树
bool isValidBST(TreeNode* root)
{
if(root == NULL)
return true;
vector<int> res;
InOrderTraverseBinaryTree(root, res);
if(res.size() < 2)
return true;
for(int i=1; i<res.size(); ++i)
{
if(res[i] <= res[i-1])
return false;
}
return true;
}
};
代码如下2:
// 中序遍历二叉树
void InOrderTraverseBinaryTree(TreeNode* root, int &pre, bool &bIsPreExist, bool &bIsSerach)
{
if(root == NULL)
return;
InOrderTraverseBinaryTree(root->left, pre, bIsPreExist, bIsSerach);
if(!bIsPreExist)
{
// 采用bIsPreExist来标记当前的节点是否存在上一节点。
bIsPreExist = true;
pre = root->val;
}
else
{
// 保证中序遍历的时候每一个节点都比上一个节点的值大,才是二叉搜索树
if(root->val <= pre)
{
bIsSerach = false;
return;
}
pre = root->val;
}
InOrderTraverseBinaryTree(root->right, pre, bIsPreExist, bIsSerach);
return;
}
class Solution {
public:
// 判断是不是有效的二叉搜索树
bool isValidBST(TreeNode* root)
{
bool bIsPreExist = false;
bool bIsSerach = true;
int pre = 0;
InOrderTraverseBinaryTree(root, pre, bIsPreExist, bIsSerach);
return bIsSerach;
}
};
100. Same Tree---利用树的遍历中任何一个均可以
问题描述:
Two binary trees are considered the same if they are structurally identical and the nodes have the same value.
Example 1:
Input: 1 1 / \ / \ 2 3 2 3 [1,2,3], [1,2,3] Output: true
Example 2:
Input: 1 1 / \ 2 2 [1,2], [1,null,2] Output: 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 isSame(TreeNode* p, TreeNode* q)
{
if(p==NULL && q==NULL)
return true;
else if(p==NULL)
return false;
else if(q==NULL)
return false;
if(p->val != q->val)
return false;
return isSame(p->left, q->left) && isSame(p->right, q->right);
}
bool isSameTree(TreeNode* p, TreeNode* q)
{
return isSame(p, q);
}
};
101. Symmetric Tree---利用树的遍历来解决
问题描述:
For example, this binary tree [1,2,2,3,4,4,3]
is symmetric:
1 / \ 2 2 / \ / \ 3 4 4 3
But the following [1,2,2,null,3,null,3]
is not:
1
/ \
2 2
\ \
3 3
问题解析:
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:
bool IsSymmetric(TreeNode *left, TreeNode *right)
{
if(left == NULL && right==NULL)
return true;
else if(left == NULL)
return false;
else if(right == NULL)
return false;
else
{
if(left->val != right->val)
return false;
return IsSymmetric(left->left, right->right) && IsSymmetric(left->right, right->left);
}
}
bool isSymmetric(TreeNode* root)
{
if(root == NULL)
return true;
return IsSymmetric(root->left, root->right);
}
};
102. Binary Tree Level Order Traversal---二叉树的层次遍历
问题描述:
For example:
Given binary tree [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
return its level order traversal as:
[ [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:
// 按照层次遍历
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> out;
if(root == NULL)
return out;
// 设置辅助队列
deque<TreeNode*>de;
de.push_back(root);
int num = 1;
int count = 0;
vector<int> res;
while(!de.empty())
{
++count;
res.push_back(de.front()->val);
if(de.front()->left != NULL)
de.push_back(de.front()->left);
if(de.front()->right != NULL)
de.push_back(de.front()->right);
de.pop_front();
if(count == num)
{
count = 0;
out.push_back(res);
res.clear();
num = de.size();
}
}
return out;
}
};
103. Binary Tree Zigzag Level Order Traversal--二叉树的Z字形层次遍历
问题描述:
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
return its zigzag level order traversal as:
[ [3], [20,9], [15,7] ]
问题解析:
1. 此题相当于二叉树的变相的层次遍历,于之前不同的是,先按照由左至右,下一层按照由右至左,再下一层又按照由左至右的'Z'字形遍历。
2. 解决此题,可以利用两个栈sta1和sta2来解决。
(1) 初始将root放在sta1里面,sta1中的每个结点,先遍历子结点的左结点,再遍历右结点,并将下层所有子结点置在sta2中。遍历一个结点,弹出一个结点,直到sta1为空。
(2) 开始遍历sta2,sta2的栈弹出一个遍历一个顺序就是由右至左的顺序,这是sta2中每个结点按照由右至左的顺序遍历,并将下层子结点放在sta1中。直到sta2为空。
(3)重复(1)和(2)的步骤,直到sta1和sta2为空。结束。
代码如下:
class Solution {
public:
// 按照层次遍历,设置两个辅助栈来做
vector<vector<int>> zigzagLevelOrder(TreeNode* root)
{
vector<vector<int>> out;
if(root == NULL)
return out;
// 设置辅助栈
stack<TreeNode*>sta1;
stack<TreeNode*>sta2;
sta1.push(root);
int num = 1;
int count = 0;
bool bLeft=false;
vector<int> res;
while(!sta1.empty() || !sta2.empty())
{
while(!sta1.empty())
{
res.push_back(sta1.top()->val);
if(sta1.top()->left != NULL)
sta2.push(sta1.top()->left);
if(sta1.top()->right != NULL)
sta2.push(sta1.top()->right);
sta1.pop();
}
if(!res.empty())
{
out.push_back(res);
res.clear();
}
while(!sta2.empty())
{
res.push_back(sta2.top()->val);
if(sta2.top()->right != NULL)
sta1.push(sta2.top()->right);
if(sta2.top()->left != NULL)
sta1.push(sta2.top()->left);
sta2.pop();
}
if(!res.empty())
{
out.push_back(res);
res.clear();
}
}
return out;
}
};
104. Maximum Depth of Binary Tree---求二叉树的深度
题目解析:
1. 此题是求一个二叉树的最大深度,指的是从根节点到其最远叶节点的层数。
2. 利用二叉树的深度遍历很快能够求出,代码如下:
代码如下:
class Solution {
public:
int maxDepth(TreeNode* root)
{
if(root == NULL)
return 0;
int left = maxDepth(root->left)+1;
int right = maxDepth(root->right)+1;
return left > right ? left : right;
}
};
105. Construct Binary Tree from Preorder and Inorder Traversal---二叉树的重建
题目解析:
1. 根据二叉树遍历的前序和中序序列来重建二叉树。
2. 如果是根据二叉树前序、中序或者中序、后序都可以重建处二叉树。但是根据二叉树的前序和后序就不能重建一个完整的二叉树。
3.对于此题流程是,前序第一个节点肯定是二叉树的根节点,然后,在中序中找出这个节点,中序序列中,这个节点之前的都是二叉树的左子树,之后的都是二叉树的右子树。然后在左子树和右子树中继续进行上述递归操作。
代码如下:
class Solution {
public:
// 根据前序和中序遍历结果,构造二叉树
TreeNode* ConstructCore(vector<int>& preorder, vector<int>& inorder, int prel, int prer, int inl, int inr)
{
if(prel>prer || inl>inr)
return NULL;
// 前序遍历的第一个节点是根节点的值
TreeNode *root = new TreeNode(preorder[prel]);
if(prel == prer)
return root;
// 在中序遍历中找到根节点的值
int i=inl;
while(i<=inr && inorder[i] != root->val)
++i;
if(i>inr)
return NULL;
int leftlength = i-inl;
if(leftlength>0)
{
// 构建左子树
root->left = ConstructCore(preorder, inorder, prel+1, prel+leftlength, inl, i-1);
}
if(i < inr)
{
// 构建右子树
root->right = ConstructCore(preorder, inorder, prel+leftlength+1, prer, i+1, inr);
}
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
if(preorder.empty() || preorder.size() != inorder.size())
return NULL;
int size = (int)preorder.size();
return ConstructCore(preorder, inorder, 0, size-1, 0, size-1);
}
};
108. Convert Sorted Array to Binary Search Tree---将排序数组转化为二叉平衡搜索树
题目描述:
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Example:
Given the sorted array: [-10,-3,0,5,9], One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST: 0 / \ -3 9 / / -10 5
题目解析:
1. 题目要求是给定一个排序数组,将其转化为一个二叉平衡搜索树。
2. 可以想到用二分查找的办法来做,以保证当前节点的左右子树平衡性。每次去中间结点为根,那么这个节点左边的都是其左子树,右边的都是其右子树。
class Solution {
public:
// 生成一个二叉平衡树
TreeNode* ConvertCore(vector<int>& nums, int l, int r)
{
if(l > r)
return NULL;
int mid = (l+r)/2;
TreeNode *root = new TreeNode(nums[mid]);
if(l == r)
return root;
if(mid > l)
root->left = ConvertCore(nums, l, mid-1);
if(mid<r)
root->right = ConvertCore(nums, mid+1, r);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums)
{
if(nums.empty())
return NULL;
int size = (int)nums.size();
return ConvertCore(nums, 0, size-1);
}
};
109. Convert Sorted List to Binary Search Tree---将排序队列转化为平衡搜索树
问题描述:
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Example:
Given the sorted linked list: [-10,-3,0,5,9], One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST: 0 / \ -3 9 / / -10 5
问题解析:
1. 此题要求和上题一样,都是将排序的一堆数转为二叉平衡搜索树。但是,这次给的不是数组,而是排序的队列。这个时候就不能直接用二分搜索了。结合中序遍历的二分搜索可以直接解决问题。
代码如下:
class Solution {
public:
TreeNode *sortedListToBST(ListNode *head)
{
int len = 0;
ListNode * node = head;
while (node != NULL)
{
node = node->next;
len++;
}
return buildTree(head, 0, len-1);
}
TreeNode *buildTree(ListNode *&node, int start, int end)
{
if (start > end) return NULL;
int mid = start + (end - start)/2;
TreeNode *left = buildTree(node, start, mid-1);
TreeNode *root = new TreeNode(node->val);
root->left = left;
node = node->next;
root->right = buildTree(node, mid+1, end);
return root;
}
};