当前位置:首页 > 洛谷 > 洛谷P3365题解:二叉树与最长递增子序列的巧妙结合解决改造二叉树

洛谷P3365题解:二叉树与最长递增子序列的巧妙结合解决改造二叉树

6个月前 (08-27)

洛谷P3365题解:二叉树与最长递增子序列的巧妙结合解决改造二叉树 洛谷题解 二叉树构建 中序遍历 最长递增子序列 动态规划 树结构 第1张

一、题目解读

洛谷P3365题目要求给定一棵二叉树中序遍历结果及部分边信息,求解其节点值的最长非递增子序列长度。本质是将树结构转化为序列问题,通过动态规划求解关键路径。

二、解题思路

核心思想为:

1. 构建二叉:利用边信息(父节点与左右子节点关系)递归生成树结构;

2. 中序遍历:获取节点值序列,因中序遍历保证左子树→根→右子树的顺序;

3. LIS算法:通过动态规划计算序列的最长递增子序列(LIS)长度,其补集即为非递增子序列长度。

三、解题步骤

1. 输入处理:读取节点值数组vals及边信息edges;

2. 构建二叉树:通过buildTree函数,利用边关系连接节点;

3. 中序遍历:调用inorder递归函数,将节点值存入seq序列;

4. 计算LIS:使用lengthOfLIS函数,通过二分查找优化动态规划,返回LIS长度;

5. 输出结果:总节点数减去LIS长度即为答案。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

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

// 构建二叉树
TreeNode* buildTree(int n, const vector<int>& vals, const vector<pair<int, int>>& edges) {
    vector<TreeNode*> nodes(n + 1);
    for (int i = 1; i <= n; ++i) {
        nodes[i] = new TreeNode(vals[i - 1]);
    }
    
    for (int i = 2; i <= n; ++i) {
        int fa = edges[i - 2].first;
        int ch = edges[i - 2].second;
        if (ch == 0) {
            nodes[fa]->left = nodes[i];
        } else {
            nodes[fa]->right = nodes[i];
        }
    }
    return nodes[1];
}

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

// 计算最长递增子序列长度
int lengthOfLIS(vector<int>& nums) {
    vector<int> dp;
    for (int num : nums) {
        auto it = lower_bound(dp.begin(), dp.end(), num);
        if (it == dp.end()) {
            dp.push_back(num);
        } else {
            *it = num;
        }
    }
    return dp.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> vals(n);
    for (int i = 0; i < n; ++i) {
        cin >> vals[i];
    }
    
    vector<pair<int, int>> edges(n - 1);
    for (int i = 0; i < n - 1; ++i) {
        cin >> edges[i].first >> edges[i].second;
    }
    
    TreeNode* root = buildTree(n, vals, edges);
    vector<int> seq;
    inorder(root, seq);
    
    int lis_len = lengthOfLIS(seq);
    cout << n - lis_len << endl;
    
    return 0;
}

五、总结

本解法关键在于中序遍历的特性与动态规划的结合。时间复杂度O(nlogn),空间复杂度O(n)。掌握此类转化思路,可高效应对树与序列相关的算法问题。

原创内容 转载请注明出处

分享给朋友:

相关文章

力扣746:三步通关最小花费爬楼梯

力扣746:三步通关最小花费爬楼梯

题目解析:站在楼梯的某个台阶时,需要支付当前台阶对应的体力值cost[i],之后可以选择向上爬1或2个台阶。最终目标是到达‌楼层顶部‌(即数组末尾之后的位置),且初始位置可选择下标0或1的台阶作为起点...

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

题目解读‌斐波那契数列是一个经典的数学问题,在计算机科学中常被用作算法教学的入门案例。这个神奇的数列从0和1开始,后续每个数字都是前两个数字之和。题目要求我们计算第n个斐波那契数,看似简单的问题背后却...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

一、题目解读    1999年NOIP提高组“导弹拦截”问题(对应洛谷P1020)要求设计导弹拦截系统:给定一组导弹高度数据,需计算最少拦截系统数量,并求最多能...

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

一、题目解读洛谷2789题要求计算n条直线在平面上两两相交时产生的不同交点数量。题目强调“不同”交点,需排除重复情况。解题关键在于如何高效枚举所有可能的交点组合,并避免重复计数。二、解题思路参考代码采...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。