二叉树高频面试题和答案( C++)

这里内容是引自微信公众号: 菜鸟名企梦同名文章,这里我稍作整理,原文是 JAVA 版,将其用 C++ 语言重写了一下,程序均本地跑过例程。 这里体现的方法并不唯一,且并不是最优的,只是提供一种解题思路,如果读者对其中问题有更好的解读,欢迎留言区交流学习。


二叉树相关问题及答案:

二叉树结构:

class TreeNode{

int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x),left(null),right(null){}
};

1. 求二叉树的最大深度

// 递归

int find_max_depth_V1(TreeNode* root)
{
	int depth = 0;
	if (!root)
	{
		return 0;
	}
	depth = 1 + max(find_max_depth_V1(root->left), find_max_depth_V1(root->right));
	return depth;
}

// 层遍历

int find_max_depth_V2(TreeNode* root)
{
	if (!root)
	{
		return 0;
	}
	int depth = 0;
	queue<TreeNode*> Q;
	Q.push(root);
	while (!Q.empty())
	{
		depth++;
		for (int i = 0; i < Q.size(); i++)
		{
			TreeNode* t = Q.front();
			Q.pop();
			if (t->left)
			{
				Q.push(t->left);
			}
			if (t->right)
			{
				Q.push(t->right);
			}
		}
	}
	return depth;
}

2. 求二叉树的最小深度

这里与最大深度不同的地方是,需要考虑二叉树仅有一边子树的情况,若直接套用最大子树的思路,取左右子树中的最小值,那么最小值永远是0。

// 递归

int find_min_depth_V1(TreeNode* root)
{
	int depth = 0;
	if (!root)
	{
		return 0;
	}
	if (!root->left)
	{
		return 1 + find_min_depth_V1(root->right);
	}
	if (!root->right)
	{
		return 1 + find_min_depth_V1(root->left);
	}
	depth = 1 + min(find_max_depth_V1(root->left), find_max_depth_V1(root->right));
	return depth;
}

// 层遍历

int find_min_depth_V2(TreeNode* root) 
{
	if (!root)
	{
		return 0;
	}
	int depth = 0;
	queue<TreeNode*> Q;
	Q.push(root);
	while (!Q.empty())
	{
		depth++;
		for (int i = 0; i < Q.size(); i++)
		{
			TreeNode* t = Q.front();
			Q.pop();
			if (!t->left && !t->right)
			{
				return depth;
			}
			if (t->left)
			{
				Q.push(t->left);
			}
			if (t->right)
			{
				Q.push(t->right);
			}
		}
	}
	return depth;
}

3. 求二叉树中节点的个数

int count_node(TreeNode* root)
{
	if (!root)
	{
		return 0;
	}
	int left = count_node(root->left);
	int right = count_node(root->right);
	
	return left + right + 1;
}

4. 求二叉树中叶子节点的个数

int count_leaf_node(TreeNode* root)
{
	if (!root)
	{
		return 0;
	}
	if (!root->left && !root->right)
	{
		return 1;
	}
	return count_leaf_node(root->left) + count_leaf_node(root->right);
}

5. 求二叉树中第 k 层节点的个数

int num_of_k_node(TreeNode* root, int k)
{
	if (!root || k<1)
	{
		return 0;
	}if (k == 1)
	{
		return 1;
	}
	int num_left = num_of_k_node(root->left, k - 1);
	int num_right = num_of_k_node(root->right, k - 1);
	return num_left + num_right;
}

6. 判断二叉树是否是平衡二叉树

int max_depth(TreeNode* root)
{
	if (!root)
	{
		return 0;
	}
	int left = max_depth(root->left);
	int right = max_depth(root->right);
	if (left==-1 || right == -1 || fabs(left-right)>1)
	{
		return -1;
	}
	return max(left,right) + 1;
}

bool isBanlanced(TreeNode* root)
{
	return max_depth(root) != -1;
}

7. 判断二叉树是否是完全二叉树

bool isCompleteTree(TreeNode* root)
{
	if (!root)
	{
		return false;
	}
	queue<TreeNode*> Q;
	Q.push(root);
	bool result = true;
	bool hasNoChild = false;
	while (!Q.empty())
	{
		TreeNode* temp = Q.front();
		Q.pop();
		if (hasNoChild)
		{
			if (temp->left || temp->right)
			{
				result = false;
				break;
			}
		}else {
				if (temp->left && temp->right)
				{
					Q.push(temp->left);
					Q.push(temp->right);
				}
				else if(temp->left && !temp->right)
				{
					Q.push(temp->left);
					hasNoChild = true;
				}
				else if (!temp->left && temp->right)
				{
					result = false;
					break;
				}
				else
				{
					hasNoChild = true;
				}
			}
	}
	return result;
}

8. 两个二叉树是否完全相同

bool isSameTree(TreeNode* root1, TreeNode*root2)
{
	if (!root1 && !root2)
	{
		return true;
	}
	else if (!root1 || !root2)
	{
		return false;
	}
	else if (root1->val != root2->val)
	{
		return false;
	}
	bool left = isSameTree(root1->left, root2->left);
	bool right = isSameTree(root1->right, root2->right);
	return left && right;
}

9. 两个二叉树是否互为镜像

bool isMirror(TreeNode* root1, TreeNode* root2)
{
	if (!root1 && !root2)
	{
		return true;
	}
	if (!root1 || !root2)
	{
		return false;
	}
	if (root1->val != root2->val)
	{
		return false;
	}
	return isMirror(root1->left, root2->right) && isMirror(root1->right, root2->left);
}

10. 翻转二叉树 or 镜像二叉树

TreeNode* mirrorTreeNode(TreeNode* root)
{
	if (!root)
	{
		return NULL;
	}
	TreeNode* left = mirrorTreeNode(root->left);
	TreeNode* right = mirrorTreeNode(root->right);
	root->left = right;
	root->right = left;
	return root;
}

11. 求两个二叉树的最低公共祖先节点

bool findNode(TreeNode* root, TreeNode* node)
{
	if (!root || !node)
	{
		return false;
	}
	if (root->val==node->val && root->left == node->left && \
		root->right == node->right)
	{
		return true;
	}
	bool found = findNode(root->left, node);
	if (!found)
	{
		found = findNode(root->right, node);
	}
	return found;
}

TreeNode* getLastCommonParent(TreeNode* root, TreeNode* node1, TreeNode* node2)
{
	if (findNode(root->left,node1))
	{
		if (findNode(root->right, node2)) {
			return root;
		}
		else {
			return getLastCommonParent(root->left, node1, node2);
		}
	}
	else
	{
		if (findNode(root->left,node2))
		{
			return root;
		}
		else
		{
			return getLastCommonParent(root->right, node1, node2);
		}
	}
}

12. 二叉树的前序遍历(迭代 or 递归)

// 迭代

vector<int> preOrder(TreeNode* root) {
	stack<TreeNode*> s;
	vector<int> v;
	if (!root)
	{
		return v;
	}
	s.push(root);
	while (!s.empty())
	{
		TreeNode* temp = s.top();
		s.pop();
		v.push_back(temp->val);
		if (temp->right)
		{
			s.push(temp->right);
		}
		if (temp->left)
		{
			s.push(temp->left);
		}
	}
	return v;
}

// 递归

void preOrder2(TreeNode* root, vector<int> &result)
{
	if (!root)
	{
		return;
	}
	result.push_back(root->val);
	preOrder2(root->left, result);
	preOrder2(root->right, result);
}

vector<int> preOrderReverse(TreeNode* root)
{
	vector<int> result;
	preOrder2(root, result);
	return result;
}

13. 二叉树的中序遍历(迭代 or 递归)

// 递归

void midOrder2(TreeNode* root, vector<int> &result)
{
	if (!root)
	{
		return;
	}
	midOrder2(root->left, result);
	result.push_back(root->val);
	midOrder2(root->right, result);
}

vector<int> midOrderReverse(TreeNode* root)
{
	vector<int> result;
	midOrder2(root, result);
	return result;
}

// 迭代

vector<int> minOrder(TreeNode* root)
{
	vector<int> v;
	stack<TreeNode*> s;
	TreeNode* temp = root;
	while (temp || !s.empty())
	{
		while (temp) {
			s.push(temp);
			temp = temp->left;
		}
		temp = s.top();
		s.pop();
		v.push_back(temp->val);
		temp = temp->right;
	}
	return v;
}

14. 二叉树的后序遍历(递归)

// 递归

void posOrder2(TreeNode* root, vector<int> &result)
{
	if (!root)
	{
		return;
	}
	posOrder2(root->left, result);
	posOrder2(root->right, result);
	result.push_back(root->val);
}

vector<int> midOrderReverse(TreeNode* root)
{
	vector<int> result;
	posOrder2(root, result);
	return result;
}

// 非递归

查找资料中基本方法都是添加一个多的标志位或者辅助栈,这里为了方便,更改了一下树节点的构成:

struct TreeNode_tag
{
	int val;
	int tag;
	TreeNode_tag* left;
	TreeNode_tag* right;
	TreeNode_tag(int x) :val(x),tag(0),left(NULL), right(NULL) {}
};

基于上面的结构,非递归版本如下:

vector<int> posOrder(TreeNode_tag* root)
{
	vector<int> v;
	stack<TreeNode_tag*> s;
	TreeNode_tag* tmp = root;
	while (tmp || !s.empty())
	{
		while (tmp) {
			s.push(tmp);
			tmp=tmp->left;
		}
		if (!s.empty())
		{
			tmp = s.top();
			if (tmp->tag)
			{
				v.push_back(tmp->val);
				s.pop();
				tmp = NULL;
			}
			else
			{
				tmp->tag = 1;
				tmp = tmp->right;
			}
		}
	}
	return v;
}

使用辅助栈


    vector<int> posOrder(TreeNode *root) {
        vector<int> result;
        stack<TreeNode*> s;
        if(!root)return result;

        TreeNode *current = root, *lastVisited = NULL;

        while (current != NULL || !s.empty()) {
            while (current != NULL) {
                s.push(current);
                current = current->left;
            }
            current = s.top(); 
            if (current->right == NULL || current->right == lastVisited) {
                s.pop();
                result.push_back(current->val);
                lastVisited = current;
                current = NULL;
            } else {
                current = current->right;
            }
        }
        return result;
    }

15. 前序、中序构造二叉树

此题《编程之美》和《剑指offer》 中均有。

// 解法1

int findPosition(vector<int> arr, int start, int end, int key)
{
	int i;
	for ( i = start; i<=end; i++)
	{
		if (arr[i] == key) {
			return i;
		}
	}
	return -1;
}

TreeNode* myBuildTree(vector<int> mid_order, int mid_start,int mid_end, vector<int> pre_order \
					, int pre_start, int pre_end)
{
	if (mid_start > mid_end)
	{
		return NULL;
	}
	TreeNode root = TreeNode(pre_order[pre_start]);
	int position = findPosition(mid_order, mid_start, mid_end, pre_order[pre_start]);
	root.left = myBuildTree(mid_order, mid_start, position - 1, pre_order, pre_start + 1, pre_start + position - mid_start);
	root.right = myBuildTree(mid_order, position + 1, mid_end, pre_order, position - mid_end + pre_end + 1, pre_end);
	return &root;
}
TreeNode* buildTree(vector<int> pre_order, vector<int> mid_order)
{
	if (pre_order.size() != mid_order.size())
	{
		return NULL;
	}
	return myBuildTree(mid_order, 0, mid_order.size()-1, pre_order, 0, pre_order.size()-1);
}

解法二(LeetCode 105 提交答案)

class Solution {
public:
	TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
		unordered_map<int, int> in_entry_idx_map;
		for (size_t i = 0; i < inorder.size(); i++)
		{
			in_entry_idx_map.emplace(inorder[i], i);
		}

		return helper(preorder, 0, preorder.size(), inorder, 0, inorder.size(), in_entry_idx_map);

	}

	TreeNode* helper(const vector<int>& preorder, int pre_s, int pre_e,
		const vector<int>& inorder, int in_s, int in_e,
		unordered_map<int, int>& in_entry_idx_map)
	{
		if (pre_s == pre_e || in_s == in_e)
		{
			return NULL;
		}

		auto idx = in_entry_idx_map.at(preorder[pre_s]);
		auto left_size = idx - in_s;
		auto node = new TreeNode(preorder[pre_s]);
		node->left = helper(preorder, pre_s + 1, pre_s + 1 + left_size,
			inorder, in_s, idx, in_entry_idx_map);
		node->right = helper(preorder, pre_s + 1 + left_size, pre_e,
			inorder, idx + 1, in_e, in_entry_idx_map);
		return node;
	}
};

16. 在二叉树中插入节点

这里的二叉树应为二叉搜索树,树中的结构有对应的大小关系:

TreeNode* insertNode(TreeNode* root, TreeNode* node)
{
	if (root->val==node->val && root->left == node->left && root->right==node->right)
	{
		return node;
	}
	TreeNode * tmp = root;
	TreeNode* last = NULL;
	while (tmp)
	{
		last = tmp;
		if (tmp->val > node->val)
		{
			tmp = tmp->left;
		}
		else
		{
			tmp = tmp->right;
		}
	}
	if (last)
	{
		if (last->val > node->val) {
			last->left = node;
		}
		else
		{
			last->right = node;
		}
	}
	return root;
}

17.输入二叉树和整数,打印出二叉树节点值等于输入整数的所有路径

void helper(TreeNode* root, int target, vector<int> s, int currentSum)
{
	currentSum += root->val;
	s.push_back(root->val);
	if (!root->left && !root->right)
	{
		if (currentSum == target) {
			for (auto i:s)
			{
				cout << i <<" ";
			}
			cout << endl;
		}
	}
	if (root->left)
	{
		helper(root->left, target, s, currentSum);
	}
	if (root->right)
	{
		helper(root->right, target, s, currentSum);
	}
	s.pop_back();
}

void findPath(TreeNode* root, int target)
{
	if (!root)
	{
		return;
	}
	vector<int> s;
	int currentSum = 0;
	helper(root, target, s, currentSum);
}

18.二叉树的搜索区间

给定两个值 k1 和 k2(k1<k2) 和一个二叉查找树的根节点,找到树中所有值在 k1 和 k2 范围内的节点,即打印所有 x 其中 x 是二叉查找树的中的节点值。返回所有升序的节点值

void searchHelper(TreeNode* root, int k1, int k2, vector<int> &v)
{
	if (!root)
	{
		return;
	}
	if (root->val>k1)
	{
		searchHelper(root->left, k1, k2, v);
	}
	if (root->val>=k1 && root->val<=k2)
	{
		v.push_back(root->val);
	}
	if (root->val < k2)
	{
		searchHelper(root->right, k1, k2, v);
	}

}

vector<int>searchRange(TreeNode* root, int k1, int k2)
{
	vector<int> result;
	searchHelper(root, k1, k2, result);
	return result;
}

19.二叉树的层次遍历

vector<vector<int>> levelOrder(TreeNode* root)
{
	vector<vector<int>> result;
	if (!root)
	{
		return result;
	}
	queue<TreeNode*> Q;
	Q.push(root);
	while (!Q.empty())
	{
		vector<int> tmp_v;
		int s = Q.size();
		for (int i = 0; i < s; i++)
		{
			TreeNode* tmp_node = Q.front();
			Q.pop();
			tmp_v.push_back(tmp_node->val);
			if (tmp_node->left)
			{
				Q.push(tmp_node->left);
			}
			if (tmp_node->right)
			{
				Q.push(tmp_node->right);
			}
		}
		result.push_back(tmp_v);
	}
	return result;
}

20.二叉树内两个节点的最长距离

分三种情况:

  1. 左子树的最大深度 + 右子树的最大深度
  2. 左子树的最大深度
  3. 右子树的最大深度

// 递归

int findMaxLen2(TreeNode* root)
{
	if (!root)
	{
		return 0;
	}
	int leftMax = 0;
	int rightMax = 0;
	if (root->left)
	{
		leftMax = find_max_depth_V1(root->left);
	}
	if (root->right)
	{
		rightMax = find_max_depth_V1(root->right);
	}
	return leftMax + rightMax;
}

// 这里参考的 《编程之美》 P241 的解法,重新构造一个树节点结构,加入各个节点的左分支最大长度和右分支最大长度

struct  TreeNode2{
	int val;
	TreeNode2* left;
	TreeNode2* right;
	int nMaxLeft;
	int nMaxright;
	TreeNode2(int x) : val(x), left(NULL), right(NULL), nMaxLeft(0), nMaxright(0){}
};

int findMaxLen(TreeNode2* root)
{
	if (!root)
	{
		return 0;
	}
	if (!root->left)  // 判断左子树最长距离
	{
		root->nMaxLeft = 0;
	}
	if (!root->right) // 判断右子树最长距离
	{
		root->nMaxright = 0;
	}
	if (root->left) // 遍历左子树
	{
		findMaxLen(root->left);
	}
	if (root->right) // 遍历右子树
	{
		findMaxLen(root->right);
	}
	if (root->left) // 求左子树的最大长度
	{
		int tmpMax = 0;
		if (root->left->nMaxLeft > root->left->nMaxright)
		{
			tmpMax = root->left->nMaxLeft;
		}
		else {
			tmpMax = root->left->nMaxright;
		}
		root->nMaxLeft = tmpMax + 1;
	}
	if (root->right)  // 求右子树的最大长度
	{
		int tmpMax = 0;
		if (root->right->nMaxLeft > root->right->nMaxright)
		{
			tmpMax = root->right->nMaxLeft;
		}
		else {
			tmpMax = root->right->nMaxright;
		}
		root->nMaxright = tmpMax + 1;
	}
	return root->nMaxLeft + root->nMaxright;
}

21. 不同的二叉树

给出n,由 1…n 为节点组成的二叉查找树有多少种

int numTrees(int n)
{
	vector<int> counts(n + 1, 0);
	counts[0] = 1;
	counts[1] = 1;
	for (int i = 2; i <=n; i++)
	{
		for (int j = 0; j < i; j++) {
			counts[i] += counts[j] * counts[i - j - 1];
		}
	}
	return counts[n];
}

22. 判断二叉树是否是合法的二叉查找树(BST)

BST 树定义为:
1.节点的左子树值要小于该点的值
2.节点右子树值要大于该点的值
3.左右子树必须是二叉查找树
4.一个节点的树也是二叉查找树

bool firstNode = true;
int lastVal = INT_MAX;
bool isValidBST(TreeNode* root)
{
	if (!root)
	{
		return true;
	}
	if (!isValidBST(root->left))
	{
		return false;
	}
	if (!firstNode && lastVal>=root->val)
	{
		return false;
	}
	firstNode = false;
	lastVal = root->val;
	if (!isValidBST(root->right))
	{
		return false;
	}
	return true;
}

这里还可以用二叉查找树中序遍历是一个递增序列的特性,使用二叉树的中序遍历进行求解,最后如果不是一个递增序列则不是,或者在中序非递归遍历过程中记录前一个节点的数值,如果是逆序的,则不是。

23.判断是否是子树关系

给定两个树 A 和 B ,看 B 是不是 A 的子树 (规定 空树 不属于任何树的子树)

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result=false;
        if (!pRoot2 || !pRoot1)
            return result;
        if (pRoot1->val==pRoot2->val)
            result= isSubTree(pRoot1,pRoot2);
        if (!result)
            result = HasSubtree(pRoot1->left,pRoot2);
        if (!result)
            result = HasSubtree(pRoot1->right,pRoot2);
        return result;
    }
    
    bool isSubTree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(!pRoot2)
            return true;
        if(!pRoot1 || pRoot1->val != pRoot2->val)
            return false;
        return isSubTree(pRoot1->left,pRoot2->left) && isSubTree(pRoot1->right,pRoot2->right);
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值