2013-08-19 12 views
8

Alright guys, I został poproszony to pytanie w wywiadzie dzisiaj i to idzie tak:Czy drzewo binarne zawiera inne drzewo?

„Powiedz jeśli jedno drzewo binarne jest zawarty wewnątrz innego drzewa binarnego lub nie (zawiera implikuje zarówno pod względem struktury i wartości węzłów)”

Myślałem o następującym podejściu:

zrównywanie większy drzewa jak:

{{{-}a{-}}b{{-}c{-}}}d{{{-}e{{-}f{-}}}g{{{-}h{-}}i{{-}j{-}}}} 

(I rzeczywiście napisać kod dla tego, {-} implikuje pusty LEF T lub tuż pod-drzewo, każdy pod drzewa jest zamknięta w nawiasach) {}

Teraz mniejszy podzbiór drzewa trzeba dopasować ten wzór:

{{.*}e{.*}}g{{{.*}h{.*}}i{{.*}j{.*}}} 

gdzie {.*} oznacza pustym lub nie puste pod-drzewo.

W momencie, w którym myślałem, będzie to prosty problem z dopasowaniem wzorca w języku java, ale zostałem oszukany. Właściwie teraz czuję, właśnie zmieniłem problem (stworzyłem jednego potwora z drugiego).

Czy istnieje prosty prosty szablon dopasowany do tych wzorów? Rozumiem, że mogą istnieć inne podejścia do rozwiązania tego problemu, a to może nie być najlepsze. Zastanawiam się tylko, czy to jest możliwe do rozwiązania.

+1

Czy "w strukturze" oznacza "ten sam obiekt" lub ".equals() [z odpowiednią implementacją]? Np. Jeśli drzewo jeden jest liściem o wartości" 4 ", a drzewo dwa ma również liść o wartości" 4 "(ale który jest obiektem innym niż drzewo), czy drzewo dwa zawiera drzewo jeden? –

+1

Nie widzę wymogu w pytaniu początkowo o używanie wyrażeń regularnych. Czy ta część pytania do wywiadu była odpowiednia? naprawdę wydaje się być niewłaściwym narzędziem całkowicie dla tej pracy –

+0

Wraz z @DarkFalcon podejrzewam, że algorytm, który * musi * przemierzyć całe drzewa, może nie być tym, na co liczyli ankieterzy. Przecież po spojrzeniu na kilka pierwszych węzły dwóch drzew, możesz określić, które poddrzewa prawdopodobnie pokrywają się, a które nie, nawet jeśli chcesz używać prezentacji ciągów drzew, o ile twoje ograniczniki są zrównoważone, nie można Robisz to po prostu sprawdzając, czy łańcuch ewentualnie zawartego drzewa jest podciągiem drzewa, które może zawierać? –

Odpowiedz

1

Nie jestem pewien, co osoba przeprowadzająca wywiad oznaczała dokładnie "zawarta w innym drzewie binarnym". Jeśli ankieter prosił o metody, aby sprawdzić, czy A był subtree B, tutaj jest jeden sposób, który nie wymaga regex na wszystkich:

  • spłaszczania drzewa A i B za pomocą preorder przechodzenie dostać struny, powiedzieć , prea i preB
  • spłaszczania drzewa a i B za pomocą inorder przechodzenia dostać sznurki, powiedzmy, INA i INB
  • Upewnij się, że to null pozostawia w struny, a także (używając spacje na przykład)
  • Sprawdź jeśli preA jest podłańcuchem preB AND inA jest podciągiem inB

Powodem, dla którego chcesz uwzględnić puste liście, jest to, że gdy wiele węzłów ma tę samą wartość, preorder i inorder mogą nie wystarczyć. Oto przykład:

  A 
     A  A 
    B  B  C 
C   D  B 
D   C  D 

Można również sprawdzić to:

checking subtrees using preorder and inorder strings

przeczytać także, aby uzyskać więcej informacji na temat przedsprzedaży i Inorder przechodzenia przez drzew binarnych:

http://en.wikipedia.org/wiki/Tree_traversal

Teraz, jeśli nie miał na myśli tylko poddrzewców, problem może stać się bardziej skomplikowany w zależności od tego, oznacza "część". Możesz spojrzeć na to pytanie jako na problem z izomorfizmem podgraphu (drzewa są tylko podzbiorem wykresów) i jest to NP-zupełny.

http://en.wikipedia.org/wiki/Subgraph_isomorphism_problem

Nie może być lepsze od podejścia drzewa są znacznie bardziej ograniczone i prostsze niż wykresach.

+1

Działa to tylko w celu wykrycia, czy jedno drzewo jest poddrzewem innego, czy nie wykrywa, czy jedno drzewo jest "zawarte w innym" (może nie jako podtekst). –

+0

Czy nie można tego dokonać za pomocą tylko jednego przejścia na przedpremierowy? Np. Jeśli generujesz ciąg podobny do lisp, gdzie '(wartość )' jest węzłem, którego wartością jest "wartość", a łańcuchy lewej i prawej podgrupy to '' i '', nie jest to pojedynczy podciąg sprawdzić wystarczające? –

+0

@JoshuaTaylor - Potrzebujesz obu czeków. Przeczytaj wątek, do którego Joanies prowadzi, na przykład, dlaczego. –

0

Można to zrobić za pomocą czeku podłańcuchów jak opisano w innych odpowiedzi, a przy użyciu tylko jeden przejścia (pre-order w zamówienie, lub po-order), tak długo, jak jesteś Drukowanie entirity każdego węzła drzewa, a nie tylko ich wartości. Na przykład, binarne drzewo jest albo

  • pusty drzewo, które będziemy drukować jako null lub
  • wartość i dwa drzewa, które możemy wydrukować jako (value left-tree right-tree), gdzie left-tree i right-tree są zastępowane przez reprezentację z lewej i prawej poddrzewi.

Każde drzewo ma teraz jednoznaczne drukowaną reprezentację, a więc drzewo T jest poddrzewo drzewa S wtedy i tylko wtedy, gdy reprezentacja ciąg T jest podciąg napisu reprezentacja S.

Na przykład drzewo

A 
/\ 
    B C 
/\ 
D E 

jest reprezentowany jako

(A (B (D null null) (E null null)) (C null null)) 

i można sprawdzić, że poddrzewa tego drzewa mają ciągi

(A (B (D null null) (E null null)) (C null null)) 
(B (D null null) (E null null)) 
(D null null) 
(E null null) 
(C null null) 

z których każdy jest podłańcuch łańcucha dla całego drzewa.

Jedynymi zastrzeżeniami są oczywiście przypadki, w których ciągi reprezentacji wartości kolidują z serializacją drzew (np. Ciągi znaków zawierają spacje lub nawiasy, & c.), Aby uczynić to odpornym, d. podjąć odpowiednie działania z ogranicznikami lub ucieczkami.

Należy również zauważyć, że nie każdy łańcuch będący podłańcuchem drzewa odpowiada podciąganiu drzewa. Na przykład ciąg null) (E jest podłańcuchem drzewa, ale nie odpowiada poddrzebieniu drzewa; tylko wtedy, gdy ciąg s jest reprezentacja drzewa t to znaczy, że jeśli s jest podciąg napisu s' z drzewa t” że t jest poddrzewo z t '.

0

Ściśle mówiąc, wyrażenie regularne nie jest przystosowane do obsługi zagnieżdżonych nawiasów. Zagnieżdżanie można dopasować za pomocą recursive regular expressions, ale aparat regex Java nie obsługuje wyrażeń rekursywnych.W Perl lub PHP, można użyć coś Wzorzec jak

{(?:(?R)|-)}\w{(?:(?R)|-)} 

dopasować jakąś strukturę drzewa, ale nie będzie jeszcze w stanie określić wartości węzłów potomnych w określonych poziomach.

Tak więc, niestety nie ma prostej prostej linii wyrażeń regularnych, która rozwiąże ten problem. Regex nie jest narzędziem, którego potrzebujesz do tego zadania.

Aby odpowiedzieć na to pytanie, chciałbym polecić konstruowania duże drzewa i małe drzewa, a następnie wywołanie largeTree.contains(smallTree) stosując następujące klasy:

public class BTreeNode 
{ 

public String value; 
public BTreeNode left; 
public BTreeNode right; 

public bool contains(BTreeNode tree) 
{ 
    bool retVal = visit(tree, this); 

    if (!retVal && left != null) 
    retVal = left.contains(tree.left); 

    if (!retVal && right != null) 
    retVal = right.contains(tree.right); 

    return retVal; 
} 

private bool visit(BTreeNode small, BTreeNode large) 
{ 
    bool retVal; 

    if (small == null) 
    { 
    retVal = true; 
    } 
    else if (small.value.equals(large.value)) 
    { 
    retVal = visit(small.left, large.left) && visit(small.right, large.right); 
    } 
    else 
    { 
    retVal = false; 
    } 

    return retVal; 
} 

} 

najgorszym przypadku, przejścia małego drzewa będą wykonywane za każdy węzeł dużego drzewa, który jest O(m * log n) gdzie m jest wielkością dużego drzewa, a n jest wielkością małego drzewa. Najgorszy przypadek można osiągnąć, gdy każdy element zarówno dużego, jak i małego drzewa jest równy, a małe drzewo jest w rzeczywistości o jeden węzeł większe niż duże drzewo.