Ist dies eine BST-Vorbestellungsüberquerung?


21

Hintergrund

Ein binärer Baum ist ein Stammbaum, dessen Knoten höchstens zwei untergeordnete Knoten haben.

Ein beschrifteter Binärbaum ist ein Binärbaum, dessen jeder Knoten mit einer positiven ganzen Zahl beschriftet ist. Außerdem sind alle Bezeichnungen unterschiedlich .

Ein BST (Binary Search Tree) ist ein beschrifteter Binärbaum, bei dem die Bezeichnung jedes Knotens größer ist als die Bezeichnung aller Knoten in seinem linken Teilbaum und kleiner als die Bezeichnung aller Knoten in seinem rechten Teilbaum. Das Folgende ist zum Beispiel eine BST:

Eine BST

Das Durchlaufen eines markierten Binärbaums vor der Bestellung wird durch den folgenden Pseudocode definiert.

function preorder(node)
    if node is null then
        return
    else
        print(node.label)
        preorder(node.left)
        preorder(node.right)

Sehen Sie sich das folgende Bild an, um eine bessere Intuition zu erhalten:

Durchquerung eines BT vorbestellen

Die Eckpunkte dieses Binärbaums werden in der folgenden Reihenfolge gedruckt:

F, B, A, D, C, E, G, I, H

Sie können mehr über BSTs lesen hier , und mehr über Pre-Order Traversal hier .

Herausforderung

Wenn Sie eine Liste von ganzen Zahlen ein , müssen Sie feststellen, ob es eine BST gibt, deren Traversal vorbestellt genau ein ausgibt .

Eingang

  • Eine nicht leere Liste eindeutiger positiver Ganzzahlen ein .
  • Optional kann die Länge von ein .

Ausgabe

  • Ein wahrer Wert, wenn ein das Durchlaufen einer BST vorbestellt.
  • Ein falscher Wert sonst.

Regeln

  • Es gelten die Standardregeln für gültige Einreichungen , E / A und Lücken .
  • Das ist , also gewinnt die kürzeste Lösung (in Bytes). Lassen Sie sich wie üblich nicht von lächerlich kurzen Lösungen in Golfsprachen davon abhalten, eine längere Antwort in der Sprache Ihrer Wahl zu verfassen.
  • Dies ist keine Regel, aber Ihre Antwort wird besser angenommen, wenn sie einen Link zum Testen der Lösung und eine Erklärung zur Funktionsweise enthält.

Beispiele

Input                   ---->   Output

[1]                     ---->   True
[1,2,3,4]               ---->   True
[5,1,4,2,3]             ---->   True
[5,4,3,2,1,6,7,8,9]     ---->   True
[4,2,1,3,6,5,7]         ---->   True
[8,3,1,6,4,7,10,14,13]  ---->   True
[2,3,1]                 ---->   False
[6,3,2,4,5,1,8,7,9]     ---->   False
[1,2,3,4,5,7,8,6]       ---->   False
[3,1,4,2]               ---->   False

Schauen Sie sich diesen Link an (mit freundlicher Genehmigung von Kevin Cruijssen ), um sich die Beispiele anzusehen.



Dürfen wir annehmen, dass alle ganzen Zahlen positiv sind?
GB

@ GB Ja. Ich werde den Beitrag jetzt bearbeiten.
Delfad0r

Antworten:


11

JavaScript (Node.js) , 49 Byte

a=>!a.some((p,i)=>a.some((q,j)=>q>p&a[j+=j>i]<p))

Probieren Sie es online!

ein0...einn-1ein0ich<j<n;einich<einj-1einich<einj

Sparen Sie dank Arnauld 1 Byte.


8

Gelee , 7 Bytes

ŒPŒ¿€4ḟ

Probieren Sie es online!

Rückgabe [4]für Traversen, ansonsten [].

Im Wesentlichen tsh-Algorithmus verwendet: die „disqualifiziert“ Bedingung für eine Pre-Order Traversal ist eine Teilfolge von 3 Elementen , die aussehen wie [mittel, hoch, niedrig] . (Zum Beispiel [20, 30, 10].)

Wir überprüfen äquivalent alle Untersequenzen beliebiger Länge, die den Index 4 in ihren Permutationslisten haben. Dabei handelt es sich um Listen, die wie folgt sortiert sind: [a 1 … a k cdb], wobei das a i sortiert ist und a i <b <c <d . (Jede solche Liste ist disqualifizierend, wenn wir uns die letzten drei Elemente ansehen, und jede Disqualifizierungsliste hat offensichtlich diese Form.)

ŒP          All subsequences.
  Œ¿€       Permutation index of each.
     4ḟ     Set difference of {4} and this list.

Beweis

Eine Vorbestellungsüberquerung enthält keine disqualifizierenden Untersequenzen

Basisfall: Traversal (•) ist die leere Liste. ✓

Induktion: Traversal (t) ist: t.root ++ Traversal (t.left) ++ Traversal (t.right) .

Sei [a, b, c] eine Folge davon. Wir werden zeigen, dass c <a <b unmöglich ist.

  • Wenn t.root = a , dann erfordert c <a <b c ∈ t.left und b ∈ t.right , so dass [a, b, c] die falsche Reihenfolge ist.
  • Verwenden Sie die Induktionshypothese, wenn a, b, c ∈ links oder a, b, c ∈ rechts ist.
  • Wenn a ∈ t.links und c ∈ t.right ist, ist c> a .

Eine Liste von verschiedenen Ganzzahlen ohne Disqualifizierung von Teilsequenzen ist das Durchlaufen einer BST vor der Bestellung

Wenn die Liste leer ist, ist dies der Durchlauf der einfachen BST.

Wenn die Liste head gefolgt von tail ist :

  • Sei less das längste Präfix des Endes von Elementen, die kleiner sind als head , und more sei der Rest der Liste.
  • Dann sind mehr [1]> Kopf und alle anderen mehr [i] auch größer als Kopf (andernfalls wäre [Kopf, mehr [1], mehr [i]] eine disqualifizierende Subsequenz).
  • Recurse: Verwandle weniger und mehr in BSTs.
  • Jetzt ist unsere Liste die Durchquerung von

                     head
                    /    \
             BST(less)   BST(more),
    

    und dieser Baum ist eine gültige BST.


1
Schöner Beweis. Eigentlich habe ich die Formel nicht bewiesen, als ich die Antwort postete. Ich hatte nur das Gefühl, dass es nach einigen Versuchen, die BST aus Eingaben zu konstruieren, richtig ist.
Dienstag,

5

Java 10, 94 Bytes

a->{var r=0>1;for(int j=a.length-1,i;j-->0;)for(i=0;i<j;)r|=a[j]>a[i]&a[j+1]<a[i++];return!r;}

Hafen von @tsh 'JavaScript-Antwort .

Probieren Sie es online aus.

Erläuterung:

a->{                      // Method with integer-array parameter and boolean return-type
  var r=0>1;              //  Result-boolean, starting at false
  for(int j=a.length-1,i;j-->0;)
                          //  Loop `j` in the range (length-1, 0]:
    for(i=0;i<j;)         //   Inner loop `i` in the range [0, j):
      r|=                 //    If any are true, change the result to true as well:
         a[j]>a[i]        //     The `j`'th item is larger than the `i`'th item
         &a[j+1]<a[i++];  //     And the `j+1`'th item is smaller than the `i`'th item
  return!r;}              //  After the nested loop, check if the boolean is still false

1
Bis Java-Boolesche Werte neu zugewiesen werden können |=. Ich nehme an, &=würde auch funktionieren?
J. Sallé

@ J.Sallé Ja, beide |=und &=arbeiten als Verknüpfungen für b = b | conditionund b = b & condition(wobei die &und |Verknüpfungen für &&und ||in den meisten Fällen natürlich sind).
Kevin Cruijssen

5

Ruby , 46 40 38 Bytes

f=->r{a,*b=r;!a||b==b&[*0..a]|b&&f[b]}

Probieren Sie es online!

Dies funktioniert, indem rekursiv das erste Element aals Pivot genommen und geprüft wird, ob der Rest des Arrays in zwei Teile geteilt werden kann (mit Hilfe von Schnitt und Vereinigung: Entfernen Sie zuerst alle Elemente> a, fügen Sie sie dann rechts erneut hinzu und prüfen Sie, ob etwas vorhanden ist geändert).


3

Retina 0.8.2 , 31 Bytes

\d+
$*
M`\b((1+)1+,).*\1\2\b
^0

Probieren Sie es online! Link enthält Testfälle. Verwendet den @ tsh-Algorithmus. Erläuterung:

\d+
$*

In Unary konvertieren.

M`\b((1+)1+,).*\1\2\b

Suchen Sie nach Zahlen, die zwischen zwei aufeinanderfolgenden absteigenden Zahlen liegen.

^0

Stellen Sie sicher, dass die Anzahl der Übereinstimmungen Null ist.


3

Perl 6 , 38 Bytes

!*.combinations(3).grep:{[>] .[1,0,2]}

Probieren Sie es online!

Erläuterung

 *.combinations(3)  # All combinations of 3 elements a,b,c
!                 .grep:{            }  # Return false if check succeeds for any combination
                         [>] .[1,0,2]   # Check whether b>a>c, that is b>a and c<a


3

Scala ( 68 67 Bytes)

def%(i:Seq[Int])= !i.combinations(3).exists(c=>c(0)<c(1)&c(0)>c(2))

Probieren Sie es online aus

Port of @ nwellnhofs Antwort .

Scala ( 122 103 Bytes)

def f(i:Seq[Int]):Boolean=if(i.size<1)1>0 else{val(s,t)=i.tail.span(_<i(0));t.forall(_>i(0))&f(s)&f(t)}

Vielen Dank an @Laikoni für die Vorschläge, beide Lösungen zu verkürzen.

Probieren Sie es online aus

Erläuterung:

  1. spanSchneiden Sie (unter Verwendung von Scala ) das Array unter Verwendung des Array-Kopfes als Aufteilungskriterium.
  2. Stellen Sie sicher, dass der erste Abschnitt des Arrays kleiner als der Kopf und der zweite Abschnitt größer als der Kopf ist.
  3. rekursiv prüfen, ob jedes Slice auch erfüllt (2)

1
Ich denke du brauchst den Platz nicht drin val (s,t), truekannst drin sein 1>0und kannst fallen, s.forall(_<i(0))&da dieser schon durch versichert sein sollte span.
Laikoni

1
Sie können die Funktion aufrufen %und das Leerzeichen def%(i:Seq[Int])=
löschen

Ihre Lösungen enthalten eine Funktionserklärung, die sich von anderen unterscheidet. Reine Ausdrücke sind viel kürzer. ;)
Dr Y Wit

Ich habe versucht, die Antwort von tsh zu portieren, habe es aber nicht geschafft, sie kurz genug zu halten. Version 1. l.zipWithIndex.foldLeft(1>0){case(r,v,i)=>r&l.zip(l.tail).slice(i+1,l.length).forall(x=>l(i)>x._1|l(i)<x._2)}. Version 2. (for(i<-l.indices)yield l.zip(l.tail).slice(i+1,l.length).forall(x =>l(i)>x._1|l(i)<x._2)).forall(x=>x). Irgendwelche Ideen, wie man diese kürzer macht?
Dr Y Wit

Algorithmus in Klartext: Prüfen Sie für jedes Element alle nebeneinander stehenden Elementpaare.
Dr Y Wit

2

05AB1E , 15 10 Bytes

ŒεD{3.IÊ}P

Port of @Lynn 's Jelly Antwort .
-5 Bytes dank @Emigna .

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung: "

Œ             # Take all sublists of the (implicit) input-list
              #  i.e. [2,3,1] → [[2],[2,3],[2,3,1],[3],[3,1],[1]]
              #  i.e. [1,2,3,4]
              #   → [[1],[1,2],[1,2,3],[1,2,3,4],[2],[2,3],[2,3,4],[3],[3,4],[4]]
 ε      }     # Map each to:
  D           #  Duplicate the current sublist on the stack
   {          #  Sort the copy
              #   i.e. [2,3,1] → [1,2,3]
              #   i.e. [2,3,4] → [2,3,4]
    3.I       #  Get the 4th (3rd 0-indexed) permutation of this list
              #   i.e. [1,2,3] → [2,3,1]
              #   i.e. [2,3,4] → [3,4,2]
       Ê      #  Check that the lists are NOT equal
              #   i.e. [2,3,1] and [2,3,1] → 0 (falsey)
              #   i.e. [2,3,4] and [3,4,2] → 1 (truthy)
         P    # Check whether all are truthy (and output implicitly)
              #  i.e. [1,1,0,1,1,1] → 0 (falsey)
              #  i.e. [1,1,1,1,1,1,1,1,1,1] → 1 (truthy)

1
Wie wäre es ŒεD{3.IÊ}P?
Emigna

1
@Emigna Ja, das wäre ja viel einfacher ...>.> Danke! :) (Und ein schönes Wochenende.)
Kevin Cruijssen

2

Haskell , 41 Bytes

f(h:t)=t==[]||all(>h)(snd$span(<h)t)&&f t

Probieren Sie es online!

Verwendet Lynns Beobachtung, dass es ausreicht, um zu überprüfen, ob es keine Untersequenz von for mid..high..low gibt . Dies bedeutet, dass für jedes Elementh die Liste der nachfolgenden tElemente ein Block von Elementen <hgefolgt von einem Block von Elementen ist >h(beide Blöcke können leer sein). Also, der Code überprüft , dass , nachdem wir das Präfix der Elemente fallen <hin t, sind die übrigen Elemente alle >h. Recursing überprüft dies für jedes Anfangselement, hbis die Liste die Länge 1 hat.

Eine mögliche Vereinfachung besteht darin, dass es ausreicht, nach Untermustern zu suchen hoch und niedrig zu suchen, wenn die letzten beiden aufeinander folgen . Leider hat Haskell keine kurze Möglichkeit, die letzten beiden Elemente zu extrahieren, wie dies von vorne mit einer Musterübereinstimmung möglich ist a:b:c. Ich habe eine kürzere Lösung gefunden, die nach mittleren, hohen und niedrigen Werten sucht , aber Eingaben wie diese werden nicht zurückgewiesen [3,1,4,2].

Formatierte Testfälle aus Laikoni .


1

Japt , 14 Bytes

d@sY ð_§XÃxÈ-Y

Japt Interpreter

Ausgänge false für BST, truefür kein BST.

Erläuterung:

d@                Run on each item X, return true if any aren't 0: 
  sY                  Ignore the numbers before this index
     ð_§XÃ            Get the indexes of numbers less than or equal to X
                          If it is a BST, this list will be e.g. [0,1,2...]
            -Y        Subtract the position within the index list from each index
                          eg. [0,1,2] -> [0,0,0] , [0,1,4] -> [0,0,2]
          xÈ          Sum the resulting array

1

Scala

Alle Ansätze sind Implementierungen der von tsh gezeigten Regel.

109

l.zipWithIndex.foldLeft(1>0){case(r,(v,i))=>r&l.zip(l.tail).slice(i+1,l.size).forall(x=>l(i)>x._1|l(i)<x._2)}

101

(for(i<-l.indices)yield l.zip(l.tail).slice(i+1,l.size).forall(x =>l(i)>x._1|l(i)<x._2)).forall(x=>x)

98

l.indices.foldLeft(1>0)((r,i)=>r&(l.zip(l.tail).slice(i+1,l.size).forall(x=>l(i)>x._1|l(i)<x._2)))

78

(for(i<-l.indices;j<-i+1 to l.size-2)yield l(i)>l(j)|l(i)<l(j+1)).forall(x=>x)

Wenn es sich um eine Funktion und nicht nur um einen Ausdruck handeln muss, muss jede Zeile mit (17 Byte) beginnen.

def%(l:Seq[Int])=

0

Oracle SQL, 177 Byte

with r(i,v)as(select rownum,value(t)from table(a)t)
select nvl(min(case when r.v<p.l and r.v>p.v then 0end),1)from r,(select i,lag(v)over(order by i)l,v from r)p where r.i+1<p.i

Da es in Oracle SQL keinen Booleschen Typ gibt, gibt query entweder 1 oder 0 zurück.

Oracle SQL 12c, 210 Byte

with function f(n ku$_objnumset,i int)return int as begin return n(i);end;
select min(case when f(c,1)>f(c,2)or f(c,1)<f(c,3)then 1else 0end)from(select value(t)c from table(powermultiset_by_cardinality(a,3))t)

Es ist in SQL nicht möglich, auf das Element des Arrays wie in PL / SQL zuzugreifen - dh a (i), daher wurde die Funktion fzu with clausediesem Zweck deklariert . Andernfalls wäre die Lösung viel kürzer gewesen.

Andere Einschränkungen

  • Löst eine Ausnahme für Arrays aus, die kürzer als 3 Elemente sind (anstatt 1 zurückzugeben)
  • Es wird davon ausgegangen, dass powermultiset_by_cardinality die Reihenfolge beibehält, obwohl dies in der Dokumentation nicht explizit angegeben ist

sqlplus Listing

SQL> set heading off
SQL> with r(i,v)as(select rownum,value(t)from table(ku$_objnumset(6,3,2,4,5,1,8,7,9))t)
  2  select nvl(min(case when r.v<p.l and r.v>p.v then 0end),1)from r,
  3  (select i,lag(v)over(order by i)l,v from r)p where r.i+1<p.i
  4  /

                                            0

SQL> with function f(n ku$_objnumset,i int)return int as begin return n(i);end;
  2  select min(case when f(c,1)>f(c,2)or f(c,1)<f(c,3)then 1else 0end)
  3  from(select value(t)c from table(powermultiset_by_cardinality(ku$_objnumset(6,3,2,4,5,1,8,7,9),3))t)
  4  /

                                                     0

SQL> with r(i,v)as(select rownum,value(t)from table(ku$_objnumset(8,3,1,6,4,7,10,14,13))t)
  2  select nvl(min(case when r.v<p.l and r.v>p.v then 0end),1)from r,
  3  (select i,lag(v)over(order by i)l,v from r)p where r.i+1<p.i
  4  /

                                            1

SQL> with function f(n ku$_objnumset,i int)return int as begin return n(i);end;
  2  select min(case when f(c,1)>f(c,2)or f(c,1)<f(c,3)then 1else 0end)
  3  from(select value(t)c from table(powermultiset_by_cardinality(ku$_objnumset(8,3,1,6,4,7,10,14,13),3))t)
  4  /

                                                     1

Online-Überprüfung apex.oracle.com

Aktualisieren

Oracle SQL, 155 Byte

with r(i,v)as(select rownum,value(t)from table(a)t)select nvl(min(case when a.v<b.v and a.v>c.v then 0end),1)r from r a,r b,r c where a.i<b.i and b.i+1=c.i

0

C, 823 Bytes (ohne Leerzeichen); 923 Bytes (einschließlich Leerzeichen)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tree
{struct tree * left;struct tree * right;int val;}tree;static int * test_p = 0;
void insert_root(tree ** root, int in)
{if (*root == NULL){*root = (tree *)calloc(1,sizeof(tree));(*root)->val = in;return;}else if (in < (*root)->val){insert_root(&((*root)->left),in);}else{insert_root(&((*root)->right),in);}}
void preorder(tree * root)
{if ( root == 0x0 ) { return; }*test_p++ = root->val;preorder(root->left);preorder(root->right);}
int main(int argc, char ** argv)
{int test_list[argc-1];memset(test_list,0,argc*sizeof(int));test_p = test_list;tree * root = (tree *)calloc(1,sizeof(tree));root->val = strtol(argv[1],0x0,10);int i = 1;while ( argv[++i] != 0x0 ){insert_root(&root,strtol(argv[i],0x0,10));}preorder(root);test_p = test_list;i = 1;while ( ( i < argc ) ){if ( *test_p != strtol(argv[i],0x0,10) ){return 0;}test_p++;i++;}return 1;}

Die lesbare Version des Programms ist unten:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct tree
{
    struct tree * left;

    struct tree * right;

    int val;

} tree;


static int * test_p = 0;

void insert_root(tree ** root, int in)
{
  if (*root == NULL)
  {
    *root = (tree *)calloc(1,sizeof(tree));

    (*root)->val = in;

    return;
  }

  else if (in < (*root)->val)
  {
    insert_root(&((*root)->left),in);
  }

  else
  {
    insert_root(&((*root)->right),in);
  }
}

void preorder(tree * root)
{
    if ( root == 0x0 ) {  return; }

        *test_p++ = root->val;

        preorder(root->left);

        preorder(root->right);

}

int main(int argc, char ** argv)
{
    int test_list[argc-1];

    memset(test_list,0,argc*sizeof(int));

    test_p = test_list;

    tree * root = (tree *)calloc(1,sizeof(tree));

    root->val = strtol(argv[1],0x0,10);

    int i = 1;

    while ( argv[++i] != 0x0 )
    {
        insert_root(&root,strtol(argv[i],0x0,10));
    }

    preorder(root);

    test_p = test_list;

    i = 1;

    while ( ( i < argc ) )
    {
        if ( *test_p != strtol(argv[i],0x0,10) )
        {
            return 0;
        }

        test_p++;

        i++;
    }

    return 1;   
}

Die Hauptmethode in diesem Programm liest die Liste der Nummern, die (angeblich) eine legitime Vorbestellungsüberquerung darstellen.

Die aufgerufene Funktion insert_root fügt die Ganzzahlen in einen binären Suchbaum ein, in dem vorherige Knoten kleinere Werte und nächste Knoten größere int-Werte enthalten.

Die Funktion preorder (root) durchläuft den Baum in einem Preorder-Traversal und verkettet gleichzeitig jede Ganzzahl, auf die der Algorithmus stößt, mit dem Int-Array test_list .

Eine abschließende while-Schleife prüft, ob jeder der int-Werte in der stdin- Liste und die in test_list bei jedem Index gleich sind. Wenn es ein Listenelement von stdin gibt , das nicht mit dem entsprechenden Element in test_list am jeweiligen Index übereinstimmt, gibt die Hauptfunktion 0 zurück . Andernfalls gibt die Hauptmethode 1 zurück .

Geben Sie echo $ status in das Bash-Terminal ein, um festzustellen, welche Hauptdaten zurückgegeben wurden . BASH gibt entweder eine 1 oder eine 0 aus.


2
Ihre Punktzahl ist diejenige, die Whitespace zählt.
Weizen Zauberer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.