É uma passagem de pré-encomenda do BST?

21

fundo

Uma árvore binária é uma árvore enraizada cujo todo nó tem no máximo dois filhos.

Uma árvore binária rotulada é uma árvore binária cujo nó é rotulado com um número inteiro positivo; além disso, todos os rótulos são distintos .

Uma BST (árvore de pesquisa binária) é uma árvore binária rotulada na qual o rótulo de cada nó é maior que os rótulos de todos os nós na subárvore esquerda e menor que os rótulos de todos os nós na subárvore direita. Por exemplo, o seguinte é um BST:

A BST

O percurso de pré-ordem de uma árvore binária rotulada é definido pelo pseudo-código a seguir.

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

Veja a imagem a seguir para obter uma melhor intuição:

Passagem de pré-encomenda de um BT

Os vértices dessa árvore binária são impressos na seguinte ordem:

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

Você pode ler mais sobre BSTs aqui e mais sobre a pré-encomenda de passagem aqui .

Desafio

Dada uma lista de números inteiros uma , sua tarefa é determinar se existe uma BST cuja passagem de pré-ordem imprima exatamente uma .

Entrada

  • Uma lista não vazia de números inteiros positivos distintos a .
  • Opcionalmente, o comprimento de a .

Saída

  • Um valor verdadeiro se uma é a passagem de pré-ordem de algum BST.
  • Um valor falsey caso contrário.

Regras

  • Regras padrão para envios válidos , E / S , brechas .
  • Esta é a , a solução mais curta (em bytes) vence. Como sempre, não permita que soluções ridiculamente curtas nos idiomas de golfe o desencorajem a postar uma resposta mais longa no idioma de sua escolha.
  • Esta não é uma regra, mas sua resposta será melhor recebida se incluir um link para testar a solução e uma explicação de como ela funciona.

Exemplos

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

Confira este link (cortesia de Kevin Cruijssen ) para dar uma olhada visual nos exemplos.

Delfad0r
fonte
Podemos assumir que todos os números inteiros são positivos?
GB
@GB Sim. Vou editar a postagem agora.
perfil completo de Delfad

Respostas:

11

JavaScript (Node.js) , 49 bytes

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

Experimente online!

Usando o fato de que para a matriz a0...an1 , a é a travessia de pré-ordem de algum BST iff 0i<j<n;ai<aj1ai<aj mantém.

Graças a Arnauld , economize 1 byte.

tsh
fonte
8

Jelly , 7 bytes

ŒPŒ¿€4ḟ

Experimente online!

Retorna [4]para travessias, caso contrário [].

Usa essencialmente o algoritmo do tsh: a condição "desqualificante" para uma travessia de pré-ordem é uma subsequência de 3 elementos que se parecem com [médio, alto, baixo] . (Por exemplo, [20, 30, 10].)

Nós equivalentemente verificar quaisquer subseqüências de qualquer comprimento que têm índice de 4 em suas listas de permutação, que são todas as listas classificadas como [a 1 ... um k cdb] onde o um i são classificadas e um i <b <c <d . (Cada lista desse tipo é desqualificante se olharmos para os três últimos elementos, e cada lista desqualificante é obviamente dessa forma.)

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

Prova

Um percurso de pré-encomenda não contém subsequências desqualificantes

Caso base: transversal (•) é a lista vazia. ✓

Indução: traversal (t) é: t.root ++ traversal (t.left) ++ traversal (t.right) .

Seja [a, b, c] uma subsequência disso. Mostraremos que c <a <b é impossível.

  • Se t.root = a , então c <a <b requer c ∈ t.left e b ∈ t.right , então [a, b, c] é a ordem errada.
  • Se a, b, c = esquerda ou a, b, c = direita , use a hipótese de indução.
  • Se a esquerda e a direita estiverem, então c> a .

Uma lista de números inteiros distintos sem subsequências desqualificantes é a passagem de pré-ordem de um BST

Se a lista estiver vazia, é a travessia do trivial BST •.

Se a lista for cabeça seguida por cauda :

  • Seja menos o prefixo mais longo da cauda dos elementos menor que o cabeçalho e mais seja o restante da lista.
  • Então mais [1]> cabeça , e todos os outros mais [i] são maiores que cabeça também (caso contrário [cabeça, mais [1], mais [i]] seria uma subsequência desqualificante)).
  • Recurse: girar menos e mais em BSTs.
  • Agora nossa lista é a travessia de

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

    e essa árvore é uma BST válida.

Lynn
fonte
1
Boa prova. Na verdade, não provei a fórmula ao postar a resposta. Eu apenas senti que está correto depois de algumas tentativas de construir o BST a partir da 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;}

Porta da resposta JavaScript @tsh ' .

Experimente online.

Explicação:

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
fonte
1
ATÉ que os booleanos Java possam ser reatribuídos |=. Eu suponho &=que também funcionaria?
J. Sallé
@ J.Sallé Sim, ambos |=e &=funcionam como atalhos para b = b | conditione b = b & condition(onde &e |são atalhos para &&e ||na maioria dos casos, é claro).
Kevin Cruijssen 19/10/10
5

Ruby , 46 40 38 bytes

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

Experimente online!

Isso funciona recursivamente, tomando o primeiro elemento acomo um pivô e verificando se o restante da matriz pode ser dividido em dois (usando interseção e união: primeiro remova todos os elementos> a, adicione-os novamente à direita e verifique se há algo alterado).

GB
fonte
3

Retina 0.8.2 , 31 bytes

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

Experimente online! O link inclui casos de teste. Usa o algoritmo do @ tsh. Explicação:

\d+
$*

Converta para unário.

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

Encontre números que estejam entre dois números descendentes consecutivos subsequentes.

^0

Verifique se o número de correspondências é zero.

Neil
fonte
3

Perl 6 , 38 bytes

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

Experimente online!

Explicação

 *.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
fonte
3

Scala ( 68 67 bytes)

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

Experimente online

Porto de @ nwellnhof's resposta .

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

Obrigado a @Laikoni pelas sugestões para reduzir as duas soluções.

Experimente online

Explicação:

  1. fatia (usando o Scala span ) a matriz usando a cabeça da matriz como critério de fatia.
  2. Confirme se a primeira fatia da matriz é menor que a cabeça e a segunda fatia é maior que a cabeça.
  3. verifique recursivamente se cada fatia também satisfaz (2)
jrook
fonte
1
Eu acho que você não precisa do espaço val (s,t), truepode ser 1>0e pode soltar, s.forall(_<i(0))&pois isso já deve estar seguro span.
Laikoni
1
Você pode chamar a função %e soltar o espaço:def%(i:Seq[Int])=
Laikoni
Suas soluções contêm uma declaração da função diferente de outras. Expressões puras são bem mais curtas. ;)
Dr. Y Wit
Eu estava tentando portar a resposta do tsh, mas não consegui obtê-lo curto o suficiente. Versão 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)}.. Versão 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).. Alguma idéia de como torná-las mais curtas?
Dr. Y Wit
Algoritmo em inglês simples: para cada elemento, verifique todos os pares de elementos próximos um do outro.
Dr. Y Wit
2

05AB1E , 15 10 bytes

ŒεD{3.IÊ}P

Porto da resposta da @Lynn Jelly .
-5 bytes graças a @Emigna .

Experimente online ou verifique todos os casos de teste .

Explicação: "

Œ             # 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
fonte
1
Que tal ŒεD{3.IÊ}P?
Emigna
1
@Emigna Sim, isso seria realmente muito mais fácil ...>.> Obrigado! :) (E ter um bom fim de semana.)
Kevin Cruijssen
2

Haskell , 41 bytes

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

Experimente online!

Usa a observação de Lynn de que é suficiente verificar se não há subsequência do para meados .. alto .. baixo . Isso significa que, para cada elemento h, a lista de elementos tque vem depois é um bloco de elementos <hseguido por um bloco de elementos >h(os dois blocos podem estar vazios). Assim, o código verifica que depois de soltar o prefixo de elementos <hem t, os restantes elementos são todos >h. A repetição verifica isso para cada elemento inicial haté que a lista tenha o comprimento 1.

Uma possível simplificação é que basta verificar subpadrões em meados de ... alto, baixo, onde os dois últimos são consecutivos. Infelizmente, o Haskell's não tem um caminho curto para extrair os dois últimos elementos, como pode ser feito de frente com uma correspondência de padrões a:b:c. Encontrei uma solução mais curta que verifica a média, a alta .. baixa , mas isso falha em rejeitar entradas como [3,1,4,2].

Casos de teste formatados retirados de Laikoni .

xnor
fonte
1

Japonês , 14 bytes

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

Intérprete Japt

Saídas falsepara BST, truesem BST.

Explicação:

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
fonte
1

Scala

Todas as abordagens são implementações da regra mostrada pelo 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 ser uma função e não apenas uma expressão, cada linha deve começar com (17 bytes)

def%(l:Seq[Int])=
Dr. Y Wit
fonte
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 não há tipo booleano no Oracle SQL, a consulta retorna 1 ou 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)

Não é possível acessar o elemento da matriz no SQL da mesma forma que no PL / SQL - ou seja, a (i), portanto, a função ffoi declarada emwith clause para esse fim. Caso contrário, a solução teria sido muito menor.

Outras limitações

  • lança uma exceção para matrizes menores que 3 elementos (em vez de retornar 1)
  • existe uma suposição de que powermultiset_by_cardinality preserva a ordem, mesmo que não esteja explicitamente declarado na documentação

listagem 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ção online apex.oracle.com

Atualizar

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
fonte
0

C, 823 bytes (sem contar os caracteres de espaço em branco); 923 bytes (incluindo espaço em branco)

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

A versão legível do programa está abaixo:

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

O método principal deste programa lê a lista de números que são (supostamente) um percurso legítimo de pré-encomenda.

A função insert_root que é chamada insere os números inteiros em uma árvore de pesquisa binária em que os nós anteriores contêm valores menores e os próximos nós contêm valores int maiores.

A função preorder (root) percorre a árvore em um percurso de preorder e concatena simultaneamente cada número inteiro que o algoritmo encontra no array int test_list .

Um loop while final testa se cada um dos valores int na lista stdin e aqueles em test_list são equivalentes em cada índice. Se houver um elemento de lista do stdin que não corresponda ao elemento correspondente em test_list no respectivo índice, a função principal retornará 0. Caso contrário, o método principal retornará 1 .

Para determinar qual principal retornou, digite echo $ status no terminal do bash. O BASH imprimirá 1 ou 0.

T. Salim
fonte
2
Sua pontuação é a que conta com espaço em branco.
Wheat Wizard