2012-11-08 71 views
0

這個問題可能有很多人問過,但它有點不同。我們有一棵二叉樹。並給你兩個節點p& q。我們必須找到最不共同的家長。但是你沒有指向根的根節點指針。爲您提供兩種內置功能:查找二叉樹中最不常見的父親?

1)BOOL same(node *p, node *q); - >如果節點相同或不相等,則返回true。

2)node* parentNode(node *c); - >返回當前節點的父節點。

如果節點c實際上是root,那麼parentNode函數會返回NULL值。 使用函數我們必須找到樹的最小公共父項。

回答

1

假設C++:

node* leastCommonParent(node *p, node *q) 
{ 
    node *pParent = parentNode(p); 
    while(pParent != 0) 
    { 
     node *qParent = parentNode(q); 
     while(qParent != 0) 
     { 
      if (0 == same(pParent, qParent)) 
       return pParent; 
      qParent = parentNode(qParent); 
     } 
     pParent = parentNode(pParent); 
    } 
    return 0; 
} 

更新:沒有使用遞歸顯式聲明變量的版本如下。我相信它可以得到改進,並且可能永遠不會在當前形式的生產代碼中使用它。

node* qParent(node *p, node *q) 
{ 
    if (p == 0 || q == 0) 
     return 0; 
    if (same(p, q) == 0) 
     return p; 
    return qParent(p, q->parent); 
} 

node* pParent(node *p, node *q) 
{ 
    return qParent(p, q) ? qParent(p, q) : pParent(p->parent, q); 
} 

node * result = pParent(p, q); 
+0

好吧..我會接受答案,但無論如何要做到這一點,而不使用臨時節點。 – m4n1c

+1

謝謝。該函數僅使用指向節點的指針,因此沒有任何節點的副本正在創建,這就是爲什麼我不完全確定爲什麼臨時節點會成爲問題。根據需求,人們可以在沒有指針的情況下使用遞歸。 –

+0

我試着說明你沒有使用額外的變量或指針來保存地址。原因是這個問題在面試中被問到了朋友。據說他不應該使用任何臨時指針或變量。 – m4n1c

6

第一步:使用parentNode功能找到從根目錄的節點p的距離d1。類似地找到來自根的節點q的距離d2。 (比方說,d2弄出來OT比d1更大)

步驟2:移動更遠節點(其曾經d值是更大的)指針d2-d1朝根的步驟。

第3步:同時向指針移動指針pq,直到它們指向同一節點並返回該節點。

基本上,它會像找到兩個鏈接列表的合併點。
檢查以下鏈接: Check if two linked lists merge. If so, where?

時間複雜度:O(N)
您的代碼將有所期待沿線:

node* LCP(node* p, node *q){ 
    int d1=0, d2=0; 
    for(node* t= p; t; t = parentNode(p), ++d1); 
    for(node* t= q; t; t = parentNode(q), ++d2); 
    if(d1>d2){ 
     swap(d1, d2); 
     swap(p, q); 
    } 
    for(int i=0; i<(d2-d1); ++i) 
     q = parentNode(q); 
    if(same(p, q)){ 
     return parentNode(p); 
    } 
    while(!same(p, q)){ 
     p = parentNode(p); 
     q = parentNode(q); 
    } 
    return p; 
} 
+0

如果'p'是'q'的祖先(甚至是'p == q'),那麼在一種情況下,你的算法將返回'p',這將失敗。 「最不常見的父母」是「父母」。我假設一個人不是自己的父母。 – st0le

+0

啊!你是對的。我現在更新了代碼來處理這個邊緣案例。 – srbhkmr