Це перехід за попереднім замовленням BST?


21

Фон

Бінарне дерево є впровадженим деревом, кожен вузол має не більше двох дітей.

Мічена бінарне дерево являє собою бінарне дерево, кожен вузол позначений з позитивним цілим числом; більше того, всі етикетки відрізняються .

БСТ (бінарне дерево пошуку) являє собою мічений бінарне дерево , в якому мітка кожного вузла більше , ніж етикетках всіх вузлів в лівому поддереве, і менше , ніж етикетках всіх вузлів в його правого піддерева. Наприклад, таке BST:

А BST

Попереднє замовлення обхід міченого двійкового дерева визначаються наступним псевдо-код.

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

Для кращої інтуїції див. Наступне зображення:

Попереднє замовлення обходу BT

Вершини цього двійкового дерева друкуються у такому порядку:

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

Більше про BST можна прочитати тут , а більше про попереднє замовлення тут .

Виклик

З урахуванням переліку цілих чисел а , ваше завдання - визначити, чи існує BST, чий обхід попереднього замовлення друкує саме а .

Вхідні дані

  • Непорожній список відмінних натуральних чисел а .
  • За бажанням, довжина а .

Вихідні дані

  • Значення " truthy", якщо а - обхід попереднього замовлення деяких BST.
  • Falsey значення в іншому випадку.

Правила

  • Застосовуються стандартні правила для дійсних подань , вводу / виводу , лазівки .
  • Це , тому найкоротше рішення (у байтах) виграє. Як завжди, не дозволяйте смішно короткі рішення гофрованих мов відштовхувати вас від публікації більш довгих відповідей на обраній вами мові.
  • Це не правило, але ваша відповідь буде краще отримана, якщо вона містить посилання для перевірки рішення та пояснення того, як воно працює.

Приклади

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

Перегляньте це посилання (люб’язно Кевін Круїссен ), щоб візуально переглянути приклади.



Чи можемо ми вважати, що всі цілі числа є позитивними?
ГБ

@GB Так. Я відредагую публікацію зараз.
Delfad0r

Відповіді:


11

JavaScript (Node.js) , 49 байт

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

Спробуйте в Інтернеті!

Використовуючи той факт, що для масиву а0...ан-1 , а - обхід попереднього замовлення деякого BST iff 0i<j<н;аi<аj-1аi<аj виконується.

Завдяки Arnauld , збережіть 1 байт.


8

Желе , 7 байт

ŒPŒ¿€4ḟ

Спробуйте в Інтернеті!

Повернення [4]для переходів, в іншому випадку [].

За суті використовує алгоритм TSH: чим «дискваліфікують» умова для обходу попереднього замовлення є підпослідовність з 3 -х елементів, виглядає як [середній, високий, низький] . (Наприклад, [20, 30, 10].)

Ми то ж саме перевірити будь-які підпослідовності будь довжини , які мають індекс 4 в їх списках перестановок, які все списки сортуються як 1 ... A до CDB] , де я сортую і я <Ь <з <d . (Кожен такий список дискваліфікує, якщо ми подивимось на останні три елементи, і кожен список, що дискваліфікує, очевидно, має таку форму.)

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

Доказ

Перехід до попереднього замовлення не містить підстав, що дискваліфікують

Базовий корпус: обхід (•) - це порожній список. ✓

Індукція: обхід (t) - це: t.root ++ traversal (t.left) ++ traversal (t.right) .

Нехай [a, b, c] є підрядчиком цього. Ми покажемо, що c <a <b неможливо.

  • Якщо t.root = a , то c <a <b вимагає c ∈ t.left і b ∈ t.right , тому [a, b, c] - неправильний порядок.
  • Якщо a, b, c ∈ t.left або a, b, c ∈ t.right , використовуйте гіпотезу про індукцію.
  • Якщо a ∈ t.left і c ∈ t.right, то c> a .

Перелік чітких цілих чисел без дискваліфікаційних підрядів є попереднім замовленням BST

Якщо список порожній, це перехід тривіальної BST •.

Якщо список голови слід хвіст :

  • Дозволяє менше буде найдовший префікс хвоста елементів менше голови , а більше - решта списку.
  • Потім більше [1]> голова та всі інші більше [i] також є більшими, ніж голова (інакше [голова, більше [1], більше [i]] буде дискваліфікуючим підпорядкуванням).
  • Рекурс: все менше і більше перетворюйте на BST.
  • Тепер наш список - це обхід

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

    і це дерево є дійсним BST.


1
Гарний доказ. Насправді я не довів формулу, коли розміщував відповідь. Я просто відчув, що це правильно після деяких спроб побудувати BST з вхідних даних.
tsh

5

Java 10, 94 байти

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

Порт @tsh 'відповідь JavaScript .

Спробуйте в Інтернеті.

Пояснення:

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
ТАК, з якими Java-булеви можуть бути перепризначені |=. Я припускаю, &=що також буде працювати?
Дж. Салле

@ J.Sallé Yep, обидва |=і &=працюють як ярлики для b = b | conditionта b = b & condition(де &і |є ярлики для, &&і ||в більшості випадків, звичайно).
Kevin Cruijssen

5

Рубі , 46 40 38 байт

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

Спробуйте в Інтернеті!

Це працює, рекурсивно приймаючи перший елемент aяк стрижневий і перевіряючи, чи можна решту масиву розділити на дві частини (використовуючи перетин та об'єднання: спочатку видаліть усі елементи> a, потім додайте їх ще раз праворуч і перевірте, чи щось має змінено).


3

Сітківка 0,8.2 , 31 байт

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

Спробуйте в Інтернеті!Посилання включає тестові випадки. Використовує алгоритм @ tsh. Пояснення:

\d+
$*

Перетворити в одинарне.

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

Знайдіть числа, що лежать між двома наступними послідовними низхідними числами.

^0

Перевірте, чи кількість сірників дорівнює нулю.




3

Скала ( 68 67 байт)

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

Спробуйте в Інтернеті

Порт @ nwellnhof - х відповіді .

Scala ( 122 103 байти)

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

Дякуємо @Laikoni за пропозиції скоротити обидва рішення.

Спробуйте в Інтернеті

Пояснення:

  1. Slice (використовуючи Scala's span) масив, використовуючи голову масиву в якості критеріїв нарізки.
  2. Переконайтесь, що перший фрагмент масиву менший за голову, а другий фрагмент більший за голову.
  3. рекурсивно перевірте, чи задоволений також кожен шматочок (2)

1
Я думаю, що вам не потрібен простір val (s,t), trueможна, 1>0і ви можете скинути, s.forall(_<i(0))&оскільки це вже повинно бути застраховано span.
Лайконі

1
Ви можете зателефонувати у функцію %та залишити пробіл:def%(i:Seq[Int])=
Laikoni

Ваші рішення містять оголошення функції на відміну від деяких інших. Чисті вирази досить короткі. ;)
Д-р Y Wit

Я намагався передати відповідь tsh, але не встиг отримати його досить коротко. Версія 1. 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)}. Версія 2. 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). Будь-які ідеї, як зробити їх коротшими?
Доктор Y Віт

Алгоритм простою англійською мовою: для кожного елемента зробіть перевірку з усіма парами елементів, що йдуть поруч.
Доктор Y Віт

2

05AB1E , 15 10 байт

ŒεD{3.IÊ}P

Порт @Lynn Jelly відповіді «s .
-5 байт завдяки @Emigna .

Спробуйте в Інтернеті або перевірте всі тестові випадки .

Пояснення: "

Œ             # 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
Як щодо ŒεD{3.IÊ}P?
Емінья

1
@Emigna Так, це було б дійсно набагато простіше ...>.> Спасибі! :) (І приємні вихідні.)
Кевін Крейссен

2

Хаскелл , 41 байт

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

Спробуйте в Інтернеті!

Використовує спостереження Лінн, що достатньо перевірити, чи немає підсліддя для середини .. високого .. низького . Це означає, що для кожного елемента hсписок елементів, tщо надходить, - це блок елементів, <hза яким йде блок елементів >h(обидва блоки можуть бути порожніми). Отже, код перевіряє, що після того, як ми скинемо префікс елементів<h уt що залишилися елементи все>h . Повторне перевіряє це для кожного початкового елемента, hпоки список не буде довжиною 1.

Потенційним спрощенням є те, що достатньо перевірити наявність підпроборів середнього рівня ... високий, низький, де останні два послідовні. На жаль, у Haskell немає короткого способу вилучення двох останніх елементів, як це можна зробити спереду з відповідним шаблономa:b:c . Я знайшов коротше рішення, на яке перевіряється середній, високий .. низький , але це не вдається відхилити такі входи, як [3,1,4,2].

Відформатовані Тестові взяті з Laikoni .


1

Japt , 14 байт

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

Перекладач Japt

Виходи falseдля BST,true для BST немає.

Пояснення:

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

Скала

Усі підходи - це реалізація правила, показаного 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)

Якщо це має бути функція, а не лише вираз, то кожен рядок повинен починатися з (17 байт)

def%(l:Seq[Int])=

0

Oracle SQL, 177 байт

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

Оскільки в Oracle SQL немає булевого типу, запит повертає або 1, або 0.

Oracle SQL 12c, 210 байт

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)

Неможливо отримати елемент доступу до масиву в SQL так само, як і в PL / SQL - тобто a (i), таким чином функція fбула оголошена вwith clause для цієї мети. Інакше рішення було б набагато коротшим.

Інші обмеження

  • кидає виняток для масивів, коротших за 3 елементи (замість повернення 1)
  • є припущення, що powermultiset_by_cardinality зберігає порядок, хоча це прямо не зазначено в документації

Перелік 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

Онлайн-перевірка apex.oracle.com

Оновлення

Oracle SQL, 155 байт

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 байти (без урахування символів пробілів); 923 байти (включаючи пробіли)

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

Читальна версія програми наведена нижче:

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

Основний метод у цій програмі читає список номерів, які є (нібито) законним проходженням попереднього замовлення.

Функція insert_root, яка називається, вставляє цілі числа в двійкове дерево пошуку, де попередні вузли містять менші значення, а наступні вузли містять більші значення int.

Функція preorder (root) перетинає дерево в обході передпорядку і одночасно з'єднує кожне ціле число, алгоритм якого надходить до int масиву test_list .

Підсумковий цикл тестування циклу, якщо кожне зі значень int у списку stdin та значення тестового списку еквівалентні для кожного індексу. Якщо є елемент списку від stdin, який не відповідає відповідному елементу в test_list у відповідному індексі, головна функція повертає 0. Ще один головний метод повертає 1 .

Щоб визначити, що головне повернулося, введіть echo $ status у термінал bash. BASH видасть або 1, або 0.


2
Ваш рахунок - це той, який рахує пробіли.
Пшеничний майстер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.