二叉树找到两个节点的最近公共祖先
题目
给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
数据范围:树上节点数满足1≤n≤10^5, 节点值val满足区间 [0,n)
要求:时间复杂度O(n)
注:本题保证二叉树中每个节点的val值均不相同。
思路
这个题目是一个典型的树型动态规划,二叉树绝大多数的难题都是动态规划,比如说判断最大的线索二叉树(LeetCode——654),比如找到树上最远距离,本质上都是动态规划
按照动态规划的思路,就是把一个很大规模的问题,变成一个一个的小规模相同类型的问题,然后把结果进行逻辑处理,步步上传。
这个题目中找最近的公共祖先按照动态规划的思维去拆分就是:
- 先在左、右子树中找看是否存在最近祖先,是否存在A、是否存在B;
- 然后一直遍历左右子树,直到按照 后序遍历的方式把整个树遍历完;
- 遍历的过程中如果某个子树存在最近祖先,就把这个节点带上;
- 最后遍历完就得到了最终的最近祖先了;
代码
#include <iostream> #include <string> using namespace std; class Tree { public : char value; Tree* r; Tree* l; }; class Res { public: char ans_; // 最近的公共祖先 bool isA_; bool isB_; Res(char ans, bool isA, bool isB):ans_(ans),isA_(isA),isB_(isB){} Res(){} }; char A = 'A'; char B = 'B'; class solution { public: void function(Tree*root) { if(!root) { //TODO: return nullptr cout <<"there is not ancestor" <<endl; return ; } Res res = prcess(root); if (res.ans_ != '') { cout << "nearst ancestor is " <<res.ans_ <<endl; } } private: Res process(Tree*node) { if(!node) { return Res('',false,false); } Res res; res.ans_ = ''; res.isA_ = false; res.isB_ = false; Res rl = process(node->l); Res rr = process(node->r); if (rl.ans_ != '') { res.ans_ = rl.ans_; res.isA_ = rl.isA_; res.isB_ = rl.isB_; } else if (rr.ans_ != '') { res.ans_ = rr.ans_; res.isA_ = rr.isA_; res.isB_ = rr.isB_; } else if (rl.isA_ || rr.isA_ || node->value == A) { res.isA_; } else (rl.isB_ || rr.isB_ || node->value == B) { res.isB_; } if(res.isA_ && res.isB_) { res.ans_ = node->value; } return res; } };