📅  最后修改于: 2023-12-03 15:10:16.761000             🧑  作者: Mango
UGC-NET CS 2017 年 12 月 2 日 - 问题 5 是一道涉及二叉树的编程问题,需要程序员实现以下两个功能:
题目要求使用 C++ 或 Java 编写代码。
测试数据的格式如下:
第一行包括一个整数 T,表示测试用例的数量。
对于每个测试用例,第一行包括一个整数 N,表示树中节点的数量。
接下来的 N - 1 行给出了树中的边。
最后一行包括两个整数,表示要查询的节点。
首先需要定义一个树节点的数据结构,例如:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
接下来,可以按照给定的节点信息构建二叉树。对于每条边 (u,v)
,把 u
作为 v
的一个子节点。构建完整个二叉树后,将根节点返回。
#define MAXN 100005
vector<int> adj[MAXN];
TreeNode* buildTree(vector<int>& values) {
unordered_map<int, TreeNode*> nodes;
for (int i = 0; i < values.size(); i++) {
int val = values[i];
nodes[i] = new TreeNode(val);
}
for (int i = 0; i < values.size() - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
bool visited[MAXN] = { false };
queue<int> Q;
Q.push(0);
visited[0] = true;
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i];
if (!visited[v]) {
visited[v] = true;
if (!nodes[u]->left) {
nodes[u]->left = nodes[v];
} else {
nodes[u]->right = nodes[v];
}
Q.push(v);
}
}
}
return nodes[0];
}
此处使用了 STL 中的 unordered_map
和 queue
数据结构,需要添加以下头文件:
#include <unordered_map>
#include <queue>
LCA 是指两个节点在二叉树中的最近公共祖先。首先需要找到两个节点所在的路径(从根节点到该节点的所有节点组成的链),并将它们转换为链表。然后,问题就变为了求两个链表的最后一个公共节点。
bool getPath(TreeNode* root, int target, vector<TreeNode*>& path) {
if (!root) return false;
path.push_back(root);
if (root->val == target)
return true;
if (getPath(root->left, target, path) || getPath(root->right, target, path))
return true;
path.pop_back();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path1;
vector<TreeNode*> path2;
getPath(root, p->val, path1);
getPath(root, q->val, path2);
int i = 0;
while (i < path1.size() && i < path2.size() && path1[i] == path2[i])
i++;
return path1[i - 1];
}
假设要从根节点开始搜索,对于当前节点,需要分别计算以下三种情况:
int getDistanceToTarget(TreeNode* root, TreeNode* target, int k, int& ans) {
if (!root) return -1;
if (root == target) {
findNodes(root, k, ans);
return 0;
}
int left = getDistanceToTarget(root->left, target, k, ans);
int right = getDistanceToTarget(root->right, target, k, ans);
if (left != -1) {
if (left + 1 == k) {
ans++;
} else {
findNodes(root->right, k - left - 2, ans);
}
return left + 1;
}
if (right != -1) {
if (right + 1 == k) {
ans++;
} else {
findNodes(root->left, k - right - 2, ans);
}
return right + 1;
}
return -1;
}
void findNodes(TreeNode* root, int k, int& ans) {
if (!root || k < 0) return;
if (k == 0) {
ans++;
return;
}
findNodes(root->left, k - 1, ans);
findNodes(root->right, k - 1, ans);
}
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
#define MAXN 100005
vector<int> adj[MAXN];
TreeNode* buildTree(vector<int>& values) {
unordered_map<int, TreeNode*> nodes;
for (int i = 0; i < values.size(); i++) {
int val = values[i];
nodes[i] = new TreeNode(val);
}
for (int i = 0; i < values.size() - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
bool visited[MAXN] = { false };
queue<int> Q;
Q.push(0);
visited[0] = true;
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i];
if (!visited[v]) {
visited[v] = true;
if (!nodes[u]->left) {
nodes[u]->left = nodes[v];
} else {
nodes[u]->right = nodes[v];
}
Q.push(v);
}
}
}
return nodes[0];
}
bool getPath(TreeNode* root, int target, vector<TreeNode*>& path) {
if (!root) return false;
path.push_back(root);
if (root->val == target)
return true;
if (getPath(root->left, target, path) || getPath(root->right, target, path))
return true;
path.pop_back();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path1;
vector<TreeNode*> path2;
getPath(root, p->val, path1);
getPath(root, q->val, path2);
int i = 0;
while (i < path1.size() && i < path2.size() && path1[i] == path2[i])
i++;
return path1[i - 1];
}
void findNodes(TreeNode* root, int k, int& ans) {
if (!root || k < 0) return;
if (k == 0) {
ans++;
return;
}
findNodes(root->left, k - 1, ans);
findNodes(root->right, k - 1, ans);
}
int getDistanceToTarget(TreeNode* root, TreeNode* target, int k, int& ans) {
if (!root) return -1;
if (root == target) {
findNodes(root, k, ans);
return 0;
}
int left = getDistanceToTarget(root->left, target, k, ans);
int right = getDistanceToTarget(root->right, target, k, ans);
if (left != -1) {
if (left + 1 == k) {
ans++;
} else {
findNodes(root->right, k - left - 2, ans);
}
return left + 1;
}
if (right != -1) {
if (right + 1 == k) {
ans++;
} else {
findNodes(root->left, k - right - 2, ans);
}
return right + 1;
}
return -1;
}
int main() {
int T;
cin >> T;
while (T--) {
for (int i = 0; i < MAXN; i++) {
adj[i].clear();
}
int n;
cin >> n;
vector<int> values(n);
for (int i = 0; i < n; i++) {
cin >> values[i];
}
TreeNode* root = buildTree(values);
int node1, node2;
cin >> node1 >> node2;
TreeNode* p = new TreeNode(node1);
TreeNode* q = new TreeNode(node2);
TreeNode* lca = lowestCommonAncestor(root, p, q);
int k;
cin >> k;
int ans = 0;
getDistanceToTarget(root, lca, k, ans);
getDistanceToTarget(root, p, k, ans);
getDistanceToTarget(root, q, k, ans);
cout << ans << endl;
}
return 0;
}
以上是本人对 UGC-NET CS 2017 年 12 月 2 日问题 5 的解答。对于涉及二叉树的问题,建议程序员先考虑如何构建二叉树、如何找到一个节点的父节点以及如何找到一个节点所在的路径,并将其转换为链表,然后再解决具体问题,这样可以避免重复计算和错误的结果。