¿Es este un recorrido de reserva de BST?

21

Fondo

Un árbol binario es un árbol enraizado cuyos nodos tienen como máximo dos hijos.

Un árbol binario etiquetado es un árbol binario cuyos nodos están etiquetados con un entero positivo; Además, todas las etiquetas son distintas .

Un BST (árbol de búsqueda binario) es un árbol binario etiquetado en el que la etiqueta de cada nodo es mayor que las etiquetas de todos los nodos en su subárbol izquierdo, y más pequeña que las etiquetas de todos los nodos en su subárbol derecho. Por ejemplo, el siguiente es un BST:

Un BST

El recorrido de preorden de un árbol binario etiquetado se define mediante el siguiente pseudocódigo.

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

Vea la siguiente imagen para obtener una mejor intuición:

Pre-pedido transversal de un BT

Los vértices de este árbol binario se imprimen en el siguiente orden:

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

Puede leer más sobre BST aquí , y más sobre el recorrido de pre-pedido aquí .

Reto

Dada una lista de enteros una , su tarea es determinar si hay un BST cuyo recorrido previo al pedido imprime exactamente una .

Entrada

  • Una lista no vacía de enteros positivos distintos una .
  • Opcionalmente, la longitud de una .

Salida

  • Un valor verdadero si una es el recorrido de preorden de algunos BST.
  • Un valor falso de lo contrario.

Reglas

  • Se aplican reglas estándar para envíos válidos , E / S , lagunas .
  • Este es el , por lo que gana la solución más corta (en bytes). Como de costumbre, no permita que soluciones ridículamente cortas en los idiomas de golf lo desalienten a publicar una respuesta más larga en el idioma de su elección.
  • Esto no es una regla, pero su respuesta será mejor recibida si incluye un enlace para probar la solución y una explicación de cómo funciona.

Ejemplos

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

Consulte este enlace (cortesía de Kevin Cruijssen ) para tener una visión visual de los ejemplos.

Delfad0r
fuente
¿Podemos suponer que todos los enteros son positivos?
GB
@GB Sí. Editaré la publicación ahora.
Delfad0r

Respuestas:

11

JavaScript (Node.js) , 49 bytes

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

Pruébalo en línea!

Usando el hecho de que para array una0 0...unanorte-1 , una es el recorrido de preorden de algunos BST iff 0 0yo<j<norte;unayo<unaj-1unayo<unaj sostiene.

Gracias a Arnauld , ahorre 1 byte.

tsh
fuente
8

Jalea , 7 bytes

ŒPŒ¿€4ḟ

Pruébalo en línea!

Devoluciones [4]para recorridos, de lo contrario [].

Utiliza esencialmente el algoritmo de tsh: la condición de "descalificación" para un recorrido de preorden es una subsecuencia de 3 elementos que se ve como [medio, alto, bajo] . (Por ejemplo, [20, 30, 10]).

Verificamos de manera equivalente cualquier subsecuencia de cualquier longitud que tenga el índice 4 en sus listas de permutación, que son todas listas ordenadas como [a 1 ... a k cdb] donde a i están ordenadas y a i <b <c <d . (Cada una de estas listas es descalificante si observamos los últimos tres elementos, y cada lista descalificadora es obviamente de esta forma).

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

Prueba

Un recorrido de preorden no contiene subsecuencias descalificantes

Caso base: transversal (•) es la lista vacía. ✓

Inducción: transversal (t) es: t.root ++ transversal (t.left) ++ transversal (t.right) .

Sea [a, b, c] una subsecuencia del presente. Mostraremos que c <a <b es imposible.

  • Si t.root = a , entonces c <a <b requiere c ∈ t.left y b ∈ t.right , entonces [a, b, c] es el orden incorrecto.
  • Si a, b, c ∈ t.izquierda o a, b, c ∈ t.derecha , utilice la hipótesis de inducción.
  • Si a ∈ t.izquierda y c ∈ t.derecha entonces c> a .

Una lista de enteros distintos sin subsecuencias descalificantes es el recorrido de preorden de un BST

Si la lista está vacía, es el recorrido del BST trivial.

Si la lista es cabeza seguida de cola :

  • Deje que menos sea ​​el prefijo más largo de la cola de elementos menos que la cabeza , y que más sea ​​el resto de la lista.
  • Entonces más [1]> cabeza , y todos los demás más [i] también son mayores que la cabeza (de lo contrario [cabeza, más [1], más [i]] sería una subsecuencia descalificadora).
  • Recurse: a su vez menos y más en BSTs.
  • Ahora nuestra lista es el recorrido de

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

    y este árbol es un BST válido.

Lynn
fuente
1
Buena prueba En realidad, no probé la fórmula cuando publiqué la respuesta. Simplemente sentí que es correcto después de algunos intentos de construir el BST a partir de la entrada.
tsh
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;}

Puerto de @tsh 'respuesta de JavaScript .

Pruébalo en línea.

Explicación:

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
Kevin Cruijssen
fuente
1
TIL con el que se pueden reasignar los booleanos de Java |=. Supongo &=que también funcionaría?
J. Sallé
@ J.Sallé Sí, ambos |=y &=funcionan como accesos directos para b = b | conditiony b = b & condition(donde los &y |son accesos directos para &&y ||en la mayoría de los casos, por supuesto).
Kevin Cruijssen
5

Ruby , 46 40 38 bytes

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

Pruébalo en línea!

Esto funciona al tomar recursivamente el primer elemento acomo pivote y verificar si el resto de la matriz se puede dividir en dos (usando intersección y unión: primero elimine todos los elementos> a, luego agréguelos nuevamente a la derecha y verifique si algo tiene cambiado)

GB
fuente
3

Retina 0.8.2 , 31 bytes

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

Pruébalo en línea! El enlace incluye casos de prueba. Utiliza el algoritmo de @ tsh. Explicación:

\d+
$*

Convierte a unario.

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

Encuentra números que se encuentran entre dos números descendentes consecutivos posteriores.

^0

Verifique que el número de coincidencias sea cero.

Neil
fuente
3

Perl 6 , 38 bytes

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

Pruébalo en línea!

Explicación

 *.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
nwellnhof
fuente
3

Scala ( 68 67 Bytes)

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

Pruébalo en línea

La respuesta del puerto de @nwellnhof .

Scala ( 122103 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)}

Gracias a @Laikoni por las sugerencias para acortar ambas soluciones.

Pruébalo en línea

Explicación:

  1. cortar (usando Scala's span) la matriz usando la cabeza de la matriz como criterio de corte.
  2. Confirme que la primera porción de la matriz es menor que la cabeza y la segunda porción es mayor que la cabeza.
  3. Verifique recursivamente que cada rebanada también satisfaga (2)
jrook
fuente
1
Creo que no necesita el espacio val (s,t), truepuede ser 1>0y puede caer s.forall(_<i(0))&ya que esto ya debería estar asegurado span.
Laikoni
1
Puedes llamar a la función % y soltar el espacio:def%(i:Seq[Int])=
Laikoni
Sus soluciones contienen declaración de la función a diferencia de alguna otra. Las expresiones puras son bastante más cortas. ;)
Dr. Y Wit
Estaba tratando de portar la respuesta de tsh, pero no pude hacerlo lo suficientemente breve. Versión 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)}.. Versión 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).. ¿Alguna idea de cómo hacer estos más cortos?
Dr. Y Wit
Algoritmo en inglés simple: para cada elemento, haga una comprobación con todos los pares de elementos que van uno al lado del otro.
Dr. Y Wit
2

05AB1E , 15 10 bytes

ŒεD{3.IÊ}P

Respuesta de Port of @Lynn 's Jelly .
-5 bytes gracias a @Emigna .

Pruébalo en línea o verifique todos los casos de prueba .

Explicación: "

Œ             # 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)
Kevin Cruijssen
fuente
1
¿Qué tal ŒεD{3.IÊ}P?
Emigna
1
@Emigna Sí, eso sería mucho más fácil ...>.> ¡Gracias! :) (Y que tengan un buen fin de semana.)
Kevin Cruijssen
2

Haskell , 41 bytes

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

Pruébalo en línea!

Utiliza la observación de Lynn de que es suficiente comprobar que no hay subsecuencia de la media ... alta ... baja . Esto significa que para cada elemento h, la lista de elementos tque viene después es un bloque de elementos <hseguido de un bloque de elementos >h(ambos bloques pueden estar vacíos). Entonces, el código verifica que después de soltar el prefijo de elementos <hent , los elementos restantes son todos>h . La repetición verifica esto para cada elemento inicial hhasta que la lista tenga la longitud 1.

Una posible simplificación es que es suficiente verificar si hay subpatrones en medio ... alto, bajo donde los dos últimos son consecutivos. Desafortunadamente, Haskell no tiene una forma corta de extraer los dos últimos elementos, como se puede hacer desde el frente con una coincidencia de patrones a:b:c. Encontré una solución más corta que busca media, alta ... baja , pero no puede rechazar entradas como[3,1,4,2] .

Casos de prueba formateados tomados de Laikoni .

xnor
fuente
1

Japt , 14 bytes

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

Intérprete Japt

Salidas false para BST,true sin BST.

Explicación:

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
Kamil Drakari
fuente
1

Scala

Todos los enfoques son implementaciones de la regla que muestra 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)

Si debe ser una función y no solo una expresión, cada línea debe comenzar con (17 bytes)

def%(l:Seq[Int])=
Dr. Y Wit
fuente
0

Oracle SQL, 177 bytes

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

Como no hay ningún tipo booleano en Oracle SQL, la consulta devuelve 1 o 0.

Oracle SQL 12c, 210 bytes

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)

No es posible acceder al elemento de la matriz en SQL de la misma manera que en PL / SQL, es decir, un (i), por lo tanto, la función fse declaró with clausepara ese propósito. De lo contrario, la solución habría sido mucho más corta.

Otras limitaciones

  • lanza una excepción para matrices de menos de 3 elementos (en lugar de devolver 1)
  • existe la suposición de que powermultiset_by_cardinality conserva el orden aunque no se indique explícitamente en la documentación

listado de 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

Verificación en línea apex.oracle.com

Actualizar

Oracle SQL, 155 bytes

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
Dr. Y Wit
fuente
0

C, 823 bytes (sin contar los espacios en blanco); 923 bytes (incluido el espacio en blanco)

#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 versión legible del programa está a continuación:

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

El método principal en este programa lee la lista de números que son (supuestamente) un recorrido legítimo de preorden.

La función insert_root que se llama inserta los enteros en un árbol de búsqueda binario donde los nodos anteriores contienen valores menores y los nodos siguientes contienen valores int más grandes.

La función de preordenar (raíz) atraviesa el árbol en una travesía de preorden y concatena simultáneamente cada número entero que el algoritmo encuentra en la matriz de prueba test_list .

Un bucle while final prueba si cada uno de los valores int en la lista stdin y aquellos en test_list son equivalentes en cada índice. Si hay un elemento de lista de stdin que no coincide con el elemento correspondiente en test_list en el índice respectivo, la función principal devuelve 0. De lo contrario, el método principal devuelve 1 .

Para determinar qué main regresó, escriba echo $ status en el terminal bash. BASH imprimirá un 1 o un 0.

T. Salim
fuente
2
Su puntaje es el que cuenta espacios en blanco.
Wheat Wizard