Apakah ini traversal pre-order BST?

21

Latar Belakang

Sebuah pohon biner adalah pohon berakar yang setiap node memiliki paling banyak dua anak.

Sebuah pohon biner berlabel adalah pohon biner yang setiap simpul diberi label dengan bilangan bulat positif; Selain itu, semua label berbeda .

Sebuah BST (pohon pencarian biner) adalah pohon biner berlabel dimana label setiap node lebih besar dari label semua node di subtree kiri, dan lebih kecil dari label semua node di subtree kanan. Misalnya, berikut ini adalah BST:

BST

The pre-order traversal dari pohon biner berlabel didefinisikan oleh pseudo-kode berikut.

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

Lihat gambar berikut untuk mendapatkan intuisi yang lebih baik:

Pre-order traversal dari BT

Simpul pohon biner ini dicetak dalam urutan berikut:

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

Anda dapat membaca lebih banyak tentang BST di sini , dan lebih banyak tentang traversal pre-order di sini .

Tantangan

Diberikan daftar bilangan bulat , tugas Anda adalah menentukan apakah ada BST yang cetakan traversal pra-cetaknya persis .aa

Memasukkan

  • Daftar bilangan bulat positif yang tidak kosong .a
  • Secara opsional, panjang .a

Keluaran

  • Nilai kebenaran jika adalah traversal pre-order dari beberapa BST.a
  • Nilai falsey sebaliknya.

Aturan

  • Aturan standar untuk pengiriman yang valid , I / O , celah berlaku.
  • Ini adalah , sehingga solusi terpendek (dalam byte) menang. Seperti biasa, jangan biarkan solusi yang sangat pendek dalam bahasa golf mencegah Anda untuk mengirim jawaban yang lebih panjang dalam bahasa pilihan Anda.
  • Ini bukan aturan, tetapi jawaban Anda akan lebih baik diterima jika itu termasuk tautan untuk menguji solusi dan penjelasan tentang cara kerjanya.

Contohnya

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

Lihatlah tautan ini (milik Kevin Cruijssen ) untuk melihat contohnya secara visual.

Delfad0r
sumber
Bisakah kita menganggap semua bilangan bulat adalah positif?
GB
@ GB Ya. Saya akan mengedit posting sekarang.
Delfad0r

Jawaban:

11

JavaScript (Node.js) , 49 byte

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

Cobalah online!

Menggunakan fakta bahwa untuk array , adalah traversal pre-order dari beberapa BST iff .a0...an1a0i<j<n;ai<aj1ai<aj

Berkat Arnauld , hemat 1 byte.

tsh
sumber
8

Jelly , 7 byte

ŒPŒ¿€4ḟ

Cobalah online!

Pengembalian [4]untuk traversal, jika tidak [].

Pada dasarnya menggunakan algoritma tsh: kondisi "mendiskualifikasi" untuk pre-order traversal adalah kelanjutan dari 3 elemen yang terlihat seperti [pertengahan, tinggi, rendah] . (Misalnya, [20, 30, 10].)

Kami ekuivalen memeriksa setiap subsequences dari setiap panjang yang memiliki indeks 4 dalam daftar permutasi mereka, yang semua daftar diurutkan seperti [a 1 ... sebuah k CDB] di mana sebuah i diurutkan dan sebuah i <b <c <d . (Setiap daftar tersebut didiskualifikasi jika kita melihat tiga elemen terakhir, dan masing-masing daftar diskualifikasi jelas dari formulir ini.)

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

Bukti

Traversal pre-order tidak mengandung bagian yang didiskualifikasi

Kasing dasar: traversal (•) adalah daftar kosong. ✓

Induksi: traversal (t) adalah: t.root ++ traversal (t.left) ++ traversal (t.right) .

Biarkan [a, b, c] menjadi bagian selanjutnya dari Perjanjian ini. Kami akan menunjukkan c <a <b tidak mungkin.

  • Jika t.root = a , maka c <a <b membutuhkan c ∈ t.left dan b ∈ t.right , jadi [a, b, c] adalah urutan yang salah.
  • Jika a, b, c ∈ t. Kiri atau a, b, c ∈ t . Benar , gunakan hipotesis induksi.
  • Jika ∈ t.left dan c ∈ t.right maka c> a .

Daftar bilangan bulat yang berbeda tanpa mendiskualifikasi urutan berikutnya adalah traversal pre-order dari BST

Jika daftar kosong, itu adalah traversal dari BST • yang sepele.

Jika daftar kepala diikuti oleh ekor :

  • Biarkan kurang menjadi awalan terpanjang ekor elemen kurang dari kepala , dan biarkan lebih menjadi sisa daftar.
  • Maka lebih banyak [1]> kepala , dan yang lainnya lebih banyak [i] lebih besar dari kepala juga (jika tidak [kepala, lebih [1], lebih [i]] akan menjadi hasil diskualifikasi).
  • Perulangan: berubah lebih sedikit dan lebih banyak menjadi BST
  • Sekarang daftar kami adalah traversal dari

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

    dan pohon ini adalah BST yang valid.

Lynn
sumber
1
Bukti bagus. Sebenarnya saya tidak membuktikan formula ketika saya memposting jawabannya. Saya hanya merasa itu benar setelah beberapa upaya untuk membangun BST dari 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;}

Port jawaban JavaScript @tsh .

Cobalah online.

Penjelasan:

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
sumber
1
TIL bahwa boolean Java dapat dipindahkan dengan |=. Saya berasumsi &=juga akan bekerja?
J. Sallé
@ J.Sallé Yep, keduanya |=dan &=berfungsi sebagai jalan pintas untuk b = b | conditiondan b = b & condition(tempat &dan |merupakan jalan pintas untuk &&dan ||dalam kebanyakan kasus tentu saja).
Kevin Cruijssen
5

Ruby , 46 40 38 byte

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

Cobalah online!

Ini bekerja dengan secara rekursif mengambil elemen pertama asebagai pivot, dan memeriksa apakah sisa array dapat dibagi menjadi dua (menggunakan persimpangan dan penyatuan: pertama hapus semua elemen> a, lalu tambahkan lagi di sebelah kanan dan periksa apakah ada sesuatu yang memiliki berubah).

GB
sumber
3

Retina 0.8.2 , 31 byte

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

Cobalah online! Tautan termasuk kasus uji. Gunakan algoritma @ tsh. Penjelasan:

\d+
$*

Konversikan ke unary.

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

Temukan angka yang terletak di antara dua angka menurun berurutan berikutnya.

^0

Pastikan jumlah kecocokan adalah nol.

Neil
sumber
3

Perl 6 , 38 byte

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

Cobalah online!

Penjelasan

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

Scala ( 68 67 Bytes)

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

Cobalah online

Jawaban Port of nwellnhof .

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

Terima kasih kepada @Laikoni untuk saran untuk membuat kedua solusi ini lebih pendek.

Cobalah online

Penjelasan:

  1. slice (using Scala's span) array menggunakan head array sebagai kriteria slicing.
  2. Konfirmasikan bahwa irisan pertama array kurang dari kepala dan irisan kedua lebih besar dari kepala.
  3. periksa secara rekursif bahwa masing-masing irisan juga memenuhi (2)
jrook
sumber
1
Saya pikir Anda tidak perlu ruang dalam val (s,t), truebisa 1>0dan Anda bisa turun s.forall(_<i(0))&karena ini sudah harus diasuransikan oleh span.
Laikoni
1
Anda dapat memanggil fungsi %dan menjatuhkan ruang:def%(i:Seq[Int])=
Laikoni
Solusi Anda mengandung deklarasi fungsi tidak seperti yang lain. Ekspresi murni cukup pendek. ;)
Dr Y Wit
Saya mencoba menjawab jawaban tsh, tetapi tidak berhasil menjawabnya dengan singkat. Versi 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 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).. Ada ide bagaimana membuat ini lebih pendek?
Dr Y Wit
Algoritma dalam bahasa Inggris sederhana: untuk setiap elemen lakukan pemeriksaan dengan semua pasangan elemen akan bersebelahan.
Dr Y Wit
2

05AB1E , 15 10 byte

ŒεD{3.IÊ}P

Port of @Lynn 's Jelly menjawab .
-5 byte terima kasih kepada @Emigna .

Cobalah secara online atau verifikasi semua kasus uji .

Penjelasan: "

Œ             # 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
sumber
1
Bagaimana dengan ŒεD{3.IÊ}P?
Emigna
1
@Emigna Ya, itu akan jauh lebih mudah ...>.> Terima kasih! :) (Dan
selamat
2

Haskell , 41 byte

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

Cobalah online!

Menggunakan pengamatan Lynn bahwa itu sudah cukup untuk memeriksa bahwa tidak ada urutan untuk pertengahan ... tinggi ... rendah . Ini berarti bahwa untuk setiap elemen h, daftar elemen tyang muncul setelahnya adalah blok elemen yang <hdiikuti oleh blok elemen >h(kedua blok mungkin kosong). Jadi, kode memeriksa bahwa setelah kita meletakkan awalan elemen <hdalam t, elemen yang tersisa semuanya >h. Berulang memeriksa ini untuk setiap elemen awal hsampai daftar panjangnya 1.

Penyederhanaan yang potensial adalah bahwa itu cukup untuk memeriksa sub-pola pertengahan .. tinggi, rendah di mana dua terakhir berturut-turut. Sayangnya, Haskell's tidak memiliki cara pendek untuk mengekstraksi dua elemen terakhir, seperti yang dapat dilakukan dari depan dengan pencocokan pola a:b:c. Saya menemukan solusi yang lebih pendek yang memeriksa mid, high..low , tetapi ini gagal untuk menolak input seperti [3,1,4,2].

Kasus uji yang diformat diambil dari Laikoni .

Tidak
sumber
1

Japt , 14 byte

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

Japt Interpreter

Output falseuntuk BST, truetanpa BST.

Penjelasan:

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

Scala

Semua pendekatan adalah implementasi dari aturan yang ditunjukkan oleh 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)

Jika itu harus fungsi dan bukan hanya ekspresi maka setiap baris harus mulai dengan (17 byte)

def%(l:Seq[Int])=
Dr Y Wit
sumber
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

Karena tidak ada tipe boolean dalam Oracle SQL, kueri mengembalikan 1 atau 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)

Itu tidak mungkin elemen akses array dalam SQL dengan cara yang sama seperti pada PL / SQL - yaitu a (i), dengan demikian fungsi fdideklarasikan with clauseuntuk tujuan itu. Kalau tidak, solusinya akan jauh lebih pendek.

Keterbatasan lainnya

  • melempar pengecualian untuk array yang lebih pendek dari 3 elemen (bukannya mengembalikan 1)
  • ada asumsi bahwa powermultiset_by_cardinality menjaga ketertiban meskipun tidak secara eksplisit dinyatakan dalam dokumentasi

daftar 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

Verifikasi online apex.oracle.com

Memperbarui

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

C, 823 byte (tidak termasuk karakter spasi); 923 byte (termasuk spasi putih)

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

Versi program yang dapat dibaca adalah di bawah ini:

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

Metode utama dalam program ini membaca daftar angka yang (diduga) merupakan preorder traversal yang sah.

Fungsi insert_root yang disebut menyisipkan integer ke dalam pohon pencarian biner di mana node sebelumnya berisi nilai yang lebih rendah dan node berikutnya berisi nilai int yang lebih besar.

Fungsi preorder (root) melintasi pohon dalam preorder traversal dan secara bersamaan menggabungkan setiap bilangan bulat algoritma datang ke test_list int array .

Final while loop menguji apakah masing-masing nilai int dalam daftar stdin dan orang-orang di test_list setara pada setiap indeks. Jika ada elemen daftar dari stdin yang gagal untuk mencocokkan elemen yang sesuai di test_list pada indeks masing-masing, fungsi utama mengembalikan 0. Lain dengan metode utama mengembalikan 1 .

Untuk menentukan main apa yang dikembalikan, ketikkan echo $ status ke terminal bash. BASH akan mencetak 1 atau 0.

T. Salim
sumber
2
Skor Anda adalah spasi yang dihitung satu.
Wheat Wizard