|
发表于 10-5-2015 11:02 AM
|
显示全部楼层
感觉可以用分治法来解决,复杂度最坏是O(M*N*min(M, N))的:
* O( J4 S) V: n) i2 J6 X6 e, F1 T/ m- struct Node{
0 w& o# [# Z9 }, _2 Q" ^9 T$ f - int val;
0 C d% h* z7 `+ E - Node* left;0 j! \1 F' b/ N- Q
- Node* right;
# G9 b3 v% L3 {4 c - Node(int v): val(v), left(nullptr), right(nullptr){}
& g; z; G, c; L/ S - };. C: Q. M$ m: D
. w3 @" E% Z& L [- vector<const Node*> getCommonPart(const Node* p, const Node* q)//以p和q为树根向下找相同结构,并以先序的存储顺序返回相同部分在树p中对应的节点指针- Y, t2 D0 U. m; x& |) b
- {. P: {: C% v2 C( ]5 c
- if(!p || !q || p->val != q->val) return vector<const Node*>();8 r' B" G, E1 t! Z
- # ]: Q2 J0 K: D# Y, L5 P' x
- vector<const Node*> cp;1 h1 i+ j# @* X: B- e9 h
- cp.push_back(p);
0 d" z2 o7 F8 x! I6 F5 P- Q8 N
2 D1 }+ B! C3 {* m) l4 |1 w- auto lp = getCommonPart(p->left, q->left);8 R- R7 W3 S' X) O) D. e
- auto rp = getCommonPart(p->right, q->right);
! M, w: p! n/ h5 L2 G- q
. ?$ f" }7 ]5 X6 K8 c1 A8 ^! S5 I- cp.insert(cp.end(), lp.begin(), lp.end());8 N# I9 H0 a( o
- cp.insert(cp.end(), rp.begin(), rp.end());7 l% Y$ g: G5 G( U5 _
- : R7 l3 T' S! K! ]8 n
- return cp;
/ ?$ u" x, Z& {7 @, x& b; [! k4 t' A6 w - }
5 l8 v$ N) @' C' S) j. J" C
B4 [3 \, Y5 _ [$ K1 e' P- vector<const Node*> getLargestCommonPart(const Node* p, const Node* q)//找出树p和树q的最大相同部分,返回相同部分在树p中对应的节点指针" y) X% B E# t5 n$ L7 `# R- ^
- {
8 k. r4 |% B& o; H" M1 D j - if(!p || !q) return vector<const Node*>();
" |- Q3 A: q" Q) n9 d! m
( |# l/ D# \8 @* `0 G' n- vector<const Node*> lcp, *pLargest = &lcp;' p3 H' W% C, o7 b6 Y
- if(p->val == q->val){' H' E( ?. F1 z/ F; E% ]- L! Z
- lcp = getCommonPart(p, q);* \% q6 f/ G9 i0 E3 D1 f
- }
! t9 x0 L! a* H8 f: b1 [/ I) K - // divide and conquer7 D& g- y! W3 l$ o
- auto p_left_lcp = getLargestCommonPart(p->left, q);" `3 h8 F2 u: F- v
- auto p_right_lcp = getLargestCommonPart(p->right, q); U# a) J6 F. b% \& i
- auto q_left_lcp = getLargestCommonPart(p, q->left);/ J2 E8 ^8 d3 {, a3 F
- auto q_right_lcp = getLargestCommonPart(p, q->right);
3 y; {& }. l1 }' ?; f - 9 Y( k9 x8 I) C y+ V3 h, s. P" l4 M
- // choose one with the largest size
2 }0 q) D( c I/ B9 R - if(pLargest->size() < p_left_lcp.size()) pLargest = &p_left_lcp;$ O+ S4 T( f, B8 C3 h4 s
- if(pLargest->size() < p_right_lcp.size()) pLargest = &p_right_lcp;$ N* b/ j/ {0 n1 D
- if(pLargest->size() < q_left_lcp.size()) pLargest = &q_left_lcp;
, e+ @: y! l3 B( t7 I - if(pLargest->size() < q_right_lcp.size()) pLargest = &q_right_lcp;
/ W+ a* e% D, b; e* D) A - 3 B5 }8 s9 O+ v/ \* [
- return *pLargest;
. f2 \ k& s: M - }) ]+ P! L2 ?; v" n1 q7 t
复制代码
+ ], P ^( b, {, T5 v( x( X上面代码得到的是最大相同结构的节点集合,如果想要恢复出这个相同的结构(做一个deep copy),则可以用树遍历的方式来做0 O8 u: p% y3 l+ x' p
- void cloneCommonPart(Node* pNew, const Node* pOld, unordered_set<const Node*>& commonSet)( V U; ^" P+ C# S; ^6 |
- { e7 p+ R! o5 C; E# I5 N
- if(commonSet.count(pOld->left)){
- B n6 \8 |; X$ m - pNew->left = new Node(pOld->left->val);: t" Z. N3 L+ e; Y1 M# o3 L
- cloneCommonPart(pNew->left, pOld->left, commonSet);
1 i% i$ J$ B- d: V/ x2 O# a - }5 S$ {" [- l( P# O- P
- if(commonSet.count(pOld->right)){5 X# n. V0 G" G d% {
- pNew->right = new Node(pOld->right->val);
- g' \! g! J, h) K( ~, P2 ` - cloneCommonPart(pNew->right, pOld->right, commonSet);( S x3 H( u, H" l7 M! w1 }# b" G( I
- }
: k/ R" t5 w d+ X - }2 ]- L* @# X6 ?2 W/ E6 i$ A
- Node* cloneCommonPart(const vector<const Node*>& cp)//相同的部分可能是任意形式的树,clone出这一相同的部分
" `) W6 b( }, A9 I9 J - {6 r/ U# z+ [% f
- if(cp.empty()) return nullptr;+ v0 s6 b6 ~9 l+ Z9 k. }
5 w+ l d8 j/ Q4 i7 X G" u- const Node* pOld = cp[0];2 z/ m; ~7 @/ F# q, h1 f! v4 V
- Node* pNew = new Node(pOld->val);( e. X- \! W; ]- b
- unordered_set<const Node*> commonSet(cp.begin(), cp.end());+ i& }& x( U+ l+ Z
- & m, p# P1 g' c' q
- cloneCommonPart(pNew, pOld, commonSet);
5 `. n$ J7 M8 ]8 F5 V) C - return pNew;
$ }' S$ `3 q" `9 u7 X - }
复制代码 |
|