找回密码
 立即注册
查看: 5|回复: 0

洛谷P3365 改造二叉树:从问题分析到代码实现

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 打卡月天数:5
  • 打卡总奖励:35
  • 最近打卡:2025-07-13 16:05:02

7

主题

2

回帖

1万

积分

VIP

积分
10018
发表于 前天 11:19 | 显示全部楼层 |阅读模式
一、问题分析

题目要求我们计算将二叉树修改为二叉搜索树(BST)所需的最少修改次数。二叉搜索树的性质是:对于任意节点,其左子树所有节点的值都小于该节点的值,右子树所有节点的值都大于该节点的值。

二、解题思路
  • 中序遍历序列‌:BST的中序遍历结果是一个严格递增序列
  • ‌问题转化‌:将原二叉树的中序遍历序列转换为严格递增序列所需的最少修改次数
  • ‌最长递增子序列(LIS)‌:最少修改次数 = 序列长度 - 最长递增子序列长度

三、C++代码实现
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespACe std;

  5. struct TreeNode {
  6. int val;
  7. TreeNode *left;
  8. TreeNode *right;
  9. TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  10. };

  11. // 构建二叉树
  12. TreeNode* buildTree(int n, const vector<int>& vals, const vector<pair<int, int>>& edges) {
  13. vector<TreeNode*> nodes(n + 1);
  14. for (int i = 1; i <= n; ++i) {
  15. nodes[i] = new TreeNode(vals[i - 1]);
  16. }

  17. for (int i = 2; i <= n; ++i) {
  18. int fa = edges[i - 2].first;
  19. int ch = edges[i - 2].second;
  20. if (ch == 0) {
  21. nodes[fa]->left = nodes[i];
  22. } else {
  23. nodes[fa]->right = nodes[i];
  24. }
  25. }
  26. return nodes[1];
  27. }

  28. // 中序遍历收集节点值
  29. void inorder(TreeNode* root, vector<int>& seq) {
  30. if (!root) return;
  31. inorder(root->left, seq);
  32. seq.push_back(root->val);
  33. inorder(root->right, seq);
  34. }

  35. // 计算最长递增子序列长度
  36. int lengthOfLIS(vector<int>& nums) {
  37. vector<int> dp;
  38. for (int num : nums) {
  39. auto it = lower_bound(dp.begin(), dp.end(), num);
  40. if (it == dp.end()) {
  41. dp.push_back(num);
  42. } else {
  43. *it = num;
  44. }
  45. }
  46. return dp.size();
  47. }

  48. int main() {
  49. ios::sync_with_stdio(false);
  50. cin.tie(nullptr);

  51. int n;
  52. cin >> n;

  53. vector<int> vals(n);
  54. for (int i = 0; i < n; ++i) {
  55. cin >> vals[i];
  56. }

  57. vector<pair<int, int>> edges(n - 1);
  58. for (int i = 0; i < n - 1; ++i) {
  59. cin >> edges[i].first >> edges[i].second;
  60. }

  61. TreeNode* root = buildTree(n, vals, edges);
  62. vector<int> seq;
  63. inorder(root, seq);

  64. int lis_len = lengthOfLIS(seq);
  65. cout << n - lis_len << endl;

  66. return 0;
  67. }
复制代码






四、 代码详解1 数据结构定义

我们首先定义树节点的结构:

2 构建二叉树

根据输入构建二叉树:

3 中序遍历

收集中序遍历序列:

4 计算最长递增子序列

使用贪心算法计算LIS长度:

五、总结

通过将问题转化为中序遍历序列的最长递增子序列问题,我们能够高效地计算出将任意二叉树修改为BST所需的最少修改次数。这种方法结合了树遍历和动态规划的思想,展示了算法设计中问题转化的重要性。

来源:洛谷P3365 改造二叉树:从问题分析到代码实现






您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

SEO网站 ( 冀ICP备2025113422号-2 )|网站地图

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表