È un attraversamento pre-ordine BST?


21

sfondo

Un albero binario è un albero radicato il cui ogni nodo ha al massimo due figli.

Un albero binario etichettato è un albero binario il cui ogni nodo è etichettato con un numero intero positivo; inoltre, tutte le etichette sono distinte .

Un BST (albero di ricerca binario) è un albero binario etichettato in cui l'etichetta di ciascun nodo è maggiore delle etichette di tutti i nodi nella sua sottostruttura sinistra e più piccola delle etichette di tutti i nodi nella sua sottostruttura destra. Ad esempio, il seguente è un BST:

A BST

L' attraversamento del preordine di un albero binario etichettato è definito dal seguente pseudo-codice.

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

Vedi la seguente immagine per ottenere una migliore intuizione:

Attraversamento del preordine di un BT

I vertici di questo albero binario sono stampati nel seguente ordine:

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

Puoi leggere di più sui BST qui e di più sull'attraversamento del preordine qui .

Sfida

Dato un elenco di numeri interi un' , il tuo compito è determinare se esiste un BST il cui attraversamento pre-ordine stampa esattamente un' .

Ingresso

  • Un elenco non vuoto di interi positivi distinti un' .
  • Facoltativamente, la lunghezza di un' .

Produzione

  • Un valore veritiero se un' è l'attraversamento del pre-ordine di alcuni BST.
  • Un valore falso altrimenti.

Regole

  • Si applicano le norme standard per invii validi , I / O , scappatoie .
  • Questo è , quindi vince la soluzione più breve (in byte). Come al solito, non lasciare che soluzioni ridicolmente brevi nelle lingue da golf ti scoraggino dal pubblicare una risposta più lunga nella tua lingua preferita.
  • Questa non è una regola, ma la tua risposta sarà meglio ricevuta se include un link per testare la soluzione e una spiegazione di come funziona.

Esempi

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

Controlla questo link (per gentile concessione di Kevin Cruijssen ) per avere uno sguardo visivo gli esempi.



Possiamo supporre che tutti i numeri interi siano positivi?
GB

@ GB Sì. Modificherò il post ora.
Delfad0r

Risposte:


11

JavaScript (Node.js) , 49 byte

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

Provalo online!

un'0...un'n-1un'0io<j<n;un'io<un'j-1un'io<un'j

Grazie ad Arnauld , risparmia 1 byte.


8

Gelatina , 7 byte

ŒPŒ¿€4ḟ

Provalo online!

Restituisce [4]per gli attraversamenti, altrimenti [].

Utilizza essenzialmente l'algoritmo di TSH: la condizione "squalificante" per un attraversamento pre-ordine è una sottosequenza di 3 elementi che si presenta come [metà, alto, basso] . (Ad esempio, [20, 30, 10].)

Abbiamo equivalentemente verificare eventuali sottosequenze di qualsiasi lunghezza che hanno indice di 4 nelle loro liste di permutazione, che sono tutti gli elenchi ordinati come [a 1 ... un k CDB] dove l' una che sono ordinati e un i <b <c <d . (Ciascuno di questi elenchi è squalificante se esaminiamo gli ultimi tre elementi e ogni elenco squalificante è ovviamente di questo modulo.)

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

Prova

Un attraversamento pre-ordine non contiene sottosequenze squalificanti

Caso base: traversal (•) è l'elenco vuoto. ✓

Induzione: traversal (t) è: t.root ++ traversal (t.left) ++ traversal (t.right) .

Sia [a, b, c] una sottosequenza del presente documento. Mostreremo che c <a <b è impossibile.

  • Se t.root = a , allora c <a <b richiede c ∈ t.left e b ∈ t.right , quindi [a, b, c] è nell'ordine sbagliato.
  • Se a, b, c ∈ t. A sinistra o a, b, c ∈ t . A destra , utilizzare l'ipotesi di induzione.
  • Se ∈ t. A sinistra e c ∈ t. A destra, quindi c> a .

Un elenco di interi distinti senza sottosequenze squalificanti è l'attraversamento del pre-ordine di un BST

Se l'elenco è vuoto, è l'attraversamento del banale BST •.

Se l'elenco è head seguito da tail :

  • Lascia che meno sia il prefisso più lungo della coda di elementi inferiore alla testa , e lascia che più sia il resto dell'elenco.
  • Quindi più [1]> head e tutti gli altri più [i] sono anche più grandi di head (altrimenti [head, more [1], more [i]] sarebbe una sottosequenza squalificante).
  • Recurse: girare di meno e più in BST.
  • Ora la nostra lista è l'attraversamento di

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

    e questo albero è un BST valido.


1
Bella prova. In realtà non ho dimostrato la formula quando inserisco la risposta. Ho appena sentito che è corretto dopo alcuni tentativi di costruire il BST dall'input.
TSH

5

Java 10, 94 byte

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;}

Porta della risposta JavaScript di @tsh .

Provalo online.

Spiegazione:

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
FINO a che i booleani di Java possono essere riassegnati |=. Presumo &=funzionerebbe anche?
J. Sallé,

@ J.Sallé Sì, entrambi |=e &=funzionano come scorciatoie per b = b | conditione b = b & condition(dove le &e |sono scorciatoie per &&e ||nella maggior parte dei casi ovviamente).
Kevin Cruijssen,

5

Rubino , 46 40 38 byte

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

Provalo online!

Questo funziona prendendo in modo ricorsivo il primo elemento acome perno e controllando se il resto dell'array può essere diviso in due (usando l'intersezione e l'unione: prima rimuovi tutti gli elementi> a, quindi aggiungili di nuovo a destra e controlla se qualcosa ha cambiato).


3

Retina 0.8.2 , 31 byte

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

Provalo online! Il link include casi di test. Utilizza l'algoritmo di @ tsh. Spiegazione:

\d+
$*

Converti in unario.

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

Trova numeri compresi tra due numeri decrescenti consecutivi successivi.

^0

Verifica che il numero di corrispondenze sia zero.


3

Perl 6 , 38 byte

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

Provalo online!

Spiegazione

 *.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 byte)

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

Provalo online

La risposta di Port of @ nwellnhof .

Scala ( 122 103 byte)

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)}

Grazie a @Laikoni per i suggerimenti per abbreviare entrambe le soluzioni.

Provalo online

Spiegazione:

  1. tagliare (usando Scala span) l'array usando la testa dell'array come criterio di taglio.
  2. Confermare che la prima sezione dell'array sia inferiore alla testa e la seconda sezione sia maggiore della testa.
  3. controllare ricorsivamente che ogni fetta soddisfi anche (2)

1
Penso che non hai bisogno di spazio val (s,t), truepuò essere 1>0e puoi lasciarlo s.forall(_<i(0))&perché questo dovrebbe già essere assicurato da span.
Laikoni,

1
Puoi chiamare la funzione %e rilasciare lo spazio:def%(i:Seq[Int])=
Laikoni

Le tue soluzioni contengono una dichiarazione della funzione a differenza di altre. Le espressioni pure sono piuttosto brevi. ;)
Dr Y Wit,

Stavo cercando di portare la risposta di tsh, ma non sono riuscito a ottenerlo abbastanza breve. Versione 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)}. Versione 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). Qualche idea su come renderli più brevi?
Dr Y Wit,

Algoritmo in un inglese semplice: per ogni elemento fai un controllo con tutte le coppie di elementi che si avvicinano.
Dr Y Wit,

2

05AB1E , 15 10 byte

ŒεD{3.IÊ}P

La risposta di Port of @Lynn 's Jelly .
-5 byte grazie a @Emigna .

Provalo online o verifica tutti i casi di test .

Spiegazione: "

Π            # 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
Che ne dici ŒεD{3.IÊ}P?
Emigna,

1
@Emigna Sì, sarebbe davvero molto più facile ...>.> Grazie! :) (E buon fine settimana.)
Kevin Cruijssen,

2

Haskell , 41 byte

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

Provalo online!

Utilizza l'osservazione di Lynn secondo cui è sufficiente verificare che non vi sia alcuna sottosequenza di for mid..high..low . Questo significa che per ogni elementoh , l'elenco di elementi tche segue è un blocco di elementi <hseguito da un blocco di elementi >h(entrambi i blocchi possono essere vuoti). Quindi, il codice verifica che dopo facciamo cadere il prefisso di elementi <hin t, gli elementi restanti sono tutti >h. La ricorrenza lo verifica per ogni elemento iniziale hfino a quando l'elenco non è lungo 1.

Una potenziale semplificazione è che è sufficiente verificare la presenza di sottoprodotti sottoproprietà a metà..alta, bassa dove gli ultimi due sono consecutivi. Sfortunatamente, Haskell's non ha un modo breve per estrarre gli ultimi due elementi, come si può fare dalla parte anteriore con una corrispondenza del modello a:b:c. Ho trovato una soluzione più breve che controlla mid, high..low , ma questo non riesce a rifiutare input come [3,1,4,2].

Casi di test formattati presi da Laikoni .


1

Japt , 14 byte

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

Interprete Japt

Uscite false per BST, truesenza BST.

Spiegazione:

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

Tutti gli approcci sono implementazioni della regola mostrata da tsh.

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)

Se deve essere una funzione e non solo un'espressione, ogni riga deve iniziare con (17 byte)

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

Poiché non esiste alcun tipo booleano in Oracle SQL, la query restituisce 1 o 0.

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)

Non è possibile accedere all'elemento dell'array in SQL nello stesso modo di in PL / SQL, ovvero a (i), quindi la funzione è fstata dichiarata inwith clause tale scopo. Altrimenti la soluzione sarebbe stata molto più breve.

Altre limitazioni

  • genera un'eccezione per le matrici più brevi di 3 elementi (anziché restituire 1)
  • si presume che powermultiset_by_cardinality preservi l'ordine anche se non è esplicitamente indicato nella documentazione

elenco sqlplus

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

Verifica online apex.oracle.com

Aggiornare

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 byte (senza contare i caratteri degli spazi bianchi); 923 byte (incluso spazio bianco)

#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;}

La versione leggibile del programma è di seguito:

#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;   
}

Il metodo principale in questo programma legge l'elenco di numeri che sono (presumibilmente) un attraversamento preordinato legittimo.

La funzione insert_root che viene chiamata inserisce gli interi in un albero di ricerca binario in cui i nodi precedenti contengono valori minori e i nodi successivi contengono valori int più grandi.

La funzione preordine (root) attraversa l'albero in un attraversamento preordine e contemporaneamente concatena ogni numero intero che l'algoritmo incontra nella matrice test_list int .

Un ciclo while finale verifica se ciascuno dei valori int nell'elenco stdin e quelli in test_list sono equivalenti in ciascun indice. Se esiste un elemento list di stdin che non corrisponde all'elemento corrispondente in test_list nel rispettivo indice, la funzione principale restituisce 0. Altrimenti il ​​metodo principale restituisce 1 .

Per determinare quale principale restituito, digitare echo $ status nel terminale bash. BASH stamperà un 1 o uno 0.


2
Il tuo punteggio è quello che conta gli spazi bianchi.
Wheat Wizard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.