笔试题29——寻找两个节点的最近公共父节点,并以该父节点为根,求其子树的节点个数

题目描述:
给定二叉树和两个顶点,编写一个程序,找到最近的共同祖先,并计算由最近的共同祖先生根的子树的大小。
在每个测试用例中,第一行包含四个整数,V(树中的顶点数,顶点数从3到10000),E(边数)和两个顶点的索引。 边数E在第二行。每个边由两个顶点表示; 父顶点的索引始终位于子节点的索引之前。 例如,连接顶点5和8的边缘由“5 8”表示,而不是由“8 5”表示。没有给出边缘的顺序。 输入中的每个连续整数都用空格分隔。
第一行数据:n,m,p,q(n个节点,m条边,两个节点索引p和q)
第二行数据:m对边
输入:
13 12 8 13
1 2 1 3 2 4 3 5 3 6 4 7 7 12 5 9 5 8 6 10 6 11 11 13
10 9 1 10
1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
输出:
3 8
1 10
思路:
根据约束条件,可以充分利用数字下标。定义这样一个数字a[100001][3],i表示当前该节点,a[i][0]用来存储该节点的父节点,a[i][1]和a[i][2]用来存储该节点的左右孩子节点。然后访问的时候,用个辅助数组标记即可。
核心代码如下:

#include <iostream>
#include <cstring>
#include <string>
using namespace std;

int a[100001][3] = { 0 };
int judge[100001] = { 0 }; //开一个辅助数组
int sum[100001] = { 0 };

int main() {

	int n, m, p, q, x, y;
	cin >> n >> m >> p >> q;
	
	//int a[100001][3] = { 0 };
	for (int i = 0; i < m; i++) {
		cin >> x >> y;
		if (a[x][1] == 0) //y是x的左或右孩子
			a[x][1] = y;
		else
			a[x][2] = y;
		a[y][0] = x;  //y的父节点是x
	
	}

	//int judge[100001] = { 0 }; //开一个辅助数组
	int ans = 0;
	while (1) {
		if (a[p][0] != 0) { //p有父节点
			judge[a[p][0]]++;
			p = a[p][0]; //p变为p的父节点
		}
		else //p没父节点,p为根节点
		{
			cout << p << " ";
			ans = p;
			break;
		}
		if (a[q][0] != 0) { //p有父节点
			judge[a[q][0]]++;
			q = a[q][0]; //q变为q的父节点
		}
		else //q没父节点,q为根节点
		{
			cout << q << " ";
			ans = q;
			break;
		}
		if (judge[p] == 2 || judge[q] == 2) { //父节点有交叉(第一次交叉的节点即为最近公共节点)
			if (judge[p] == 2) {  
				cout << p << " ";
				ans = p;
			}
			else{
				cout << q << " ";
				ans = q;
			}
			break;
		}
	}
	//求解以最近公共父节点为根的子树个数
	//int sum[100001] = { 0 };
	int index = 1; //存放子树节点个数
	sum[1] = ans; //sum[1]存放找到的最近的公共父节点
	int step = 1;
	while (step <= index) {
		if (a[sum[step]][1] != 0)  //根有左孩子
			sum[++index] = a[sum[step]][1]; //将其左孩子加入到数组中
		if (a[sum[step]][2] != 0)  //根有右孩子
			sum[++index] = a[sum[step]][2];  //将其右孩子加入到数组中
		step++; //数组向前移动一位继续判断子孩子是否有孩子节点
	}
	cout << index << endl;
	return 0;
}

参考链接:https://blog.csdn.net/hqh131360239/article/details/88097680

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值