Đây có phải là một BST đặt hàng trước?


21

Lý lịch

Một cây nhị phân là một cây bắt nguồn mà mỗi nút có ít nhất hai đứa con.

Một cây nhị phân được dán nhãn là một cây nhị phân mà mỗi nút được dán nhãn với một số nguyên dương; hơn nữa, tất cả các nhãn là khác biệt .

Một BST (cây tìm kiếm nhị phân) là một cây nhị phân được dán nhãn trong đó nhãn của mỗi nút lớn hơn các nhãn của tất cả các nút trong cây con trái của nó, và nhỏ hơn so với các nhãn của tất cả các nút trong cây con phải của nó. Chẳng hạn, sau đây là BST:

BST

Truyền tải theo thứ tự trước của cây nhị phân có nhãn được xác định bởi mã giả sau đây.

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

Xem hình ảnh sau đây để có được trực giác tốt hơn:

Đặt hàng trước của BT

Các đỉnh của cây nhị phân này được in theo thứ tự sau:

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

Bạn có thể đọc thêm về các BST tại đây và biết thêm về dịch vụ đặt hàng trước tại đây .

Thử thách

Đưa ra một danh sách các số nguyên một , nhiệm vụ của bạn là xác định xem có BST nào có giao dịch đặt hàng trước in chính xác không một .

Đầu vào

  • Một danh sách không trống của các số nguyên dương khác biệt một .
  • Tùy chọn, chiều dài của một .

Đầu ra

  • Một truthy giá trị nếu một là traversal đặt hàng trước của một số BST.
  • Một giá trị falsey khác.

Quy tắc

  • Quy tắc chuẩn cho đệ trình hợp lệ , I / O , sơ hở áp dụng.
  • Đây là , vì vậy giải pháp ngắn nhất (tính bằng byte) sẽ thắng. Như thường lệ, đừng để các giải pháp ngắn một cách lố bịch trong các ngôn ngữ golf không khuyến khích bạn đăng câu trả lời dài hơn bằng ngôn ngữ bạn chọn.
  • Đây không phải là một quy tắc, nhưng câu trả lời của bạn sẽ được nhận tốt hơn nếu nó bao gồm một liên kết để kiểm tra giải pháp và giải thích về cách thức hoạt động của nó.

Ví dụ

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

Kiểm tra liên kết này (lịch sự của Kevin Cruijssen ) để có cái nhìn trực quan về các ví dụ.



Chúng ta có thể giả sử tất cả các số nguyên là tích cực?
GB

@ GB Có. Tôi sẽ chỉnh sửa bài viết bây giờ.
Delfad0r

Câu trả lời:


11

JavaScript (Node.js) , 49 byte

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

Hãy thử trực tuyến!

Sử dụng thực tế là cho mảng một0...mộtn-1 , một là traversal đặt hàng trước của một số BST iff 0tôi<j<n;mộttôi<mộtj-1mộttôi<mộtj giữ.

Nhờ Arnauld , tiết kiệm 1 byte.


8

Thạch , 7 byte

ŒPŒ¿€4ḟ

Hãy thử trực tuyến!

Trả về [4]cho giao dịch, nếu không [].

Về cơ bản sử dụng thuật toán của tsh: điều kiện "không đủ tiêu chuẩn" cho giao dịch đặt hàng trước là một chuỗi gồm 3 phần tử trông giống như [giữa, cao, thấp] . (Ví dụ: [20, 30, 10].)

Chúng tôi tương đương kiểm tra bất kỳ subsequences của bất kỳ chiều dài có chỉ số 4 trong danh sách hoán vị của họ, đó là tất cả danh sách được sắp xếp như [a 1 ... một k cdb] nơi một tôi đều được sắp xếp và một i <b <c <d . (Mỗi danh sách như vậy là không đủ tiêu chuẩn nếu chúng ta xem xét ba yếu tố cuối cùng và mỗi danh sách không đủ tiêu chuẩn rõ ràng thuộc dạng này.)

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

Bằng chứng

Một giao dịch đặt hàng trước không chứa các phần sau không đủ tiêu chuẩn

Trường hợp cơ sở: traversal (•) là danh sách trống. ✓

Cảm ứng: traversal (t) là: t.root ++ traversal (t.left) ++ traversal (t.right) .

Đặt [a, b, c] là một phần tiếp theo của tài liệu này. Chúng tôi sẽ hiển thị c <a <b là không thể.

  • Nếu t.root = a , thì c <a <b yêu cầu c ∈ t.leftb ∈ t.right , vì vậy [a, b, c] là thứ tự sai.
  • Nếu a, b, c t.left hoặc a, b, c ∈ t.right , hãy sử dụng giả thuyết cảm ứng.
  • Nếu a ∈ t.leftc ∈ t.right thì c> a .

Danh sách các số nguyên riêng biệt mà không đủ tiêu chuẩn là các giao dịch đặt hàng trước của BST

Nếu danh sách trống, đó là truyền tải của BST tầm thường •.

Nếu danh sách là đầu theo sau đuôi :

  • Đặt ít hơn là tiền tố dài nhất của đuôi các phần tử nhỏ hơn phần đầu và để phần lớn là phần còn lại của danh sách.
  • Sau đó, nhiều [1]> đầu và tất cả các [i] khác cũng lớn hơn đầu (nếu không [đầu, nhiều [1], nhiều [i]] sẽ là một chuỗi không đủ tiêu chuẩn).
  • Recurse: biến ít hơnnhiều hơn thành BST.
  • Bây giờ danh sách của chúng tôi là truyền tải

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

    và cây này là một BST hợp lệ.


1
Bằng chứng tốt đẹp. Thật ra tôi đã không chứng minh được công thức khi tôi đăng câu trả lời. Tôi chỉ cảm thấy rằng nó là chính xác sau một số nỗ lực để xây dựng BST từ đầu vào.
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;}

Cổng của câu trả lời JavaScript của @tsh .

Hãy thử trực tuyến.

Giải trình:

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
TIL rằng booleans Java có thể được gán lại |=. Tôi giả sử &=cũng sẽ làm việc?
J. Sallé

@ J.Sallé Yep, cả hai |=&=hoạt động như các phím tắt cho b = b | conditionb = b & condition(trong đó &|là các phím tắt cho &&||trong hầu hết các trường hợp tất nhiên).
Kevin Cruijssen

5

Ruby , 46 40 38 byte

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

Hãy thử trực tuyến!

Điều này hoạt động bằng cách lấy đệ quy phần tử đầu tiên alàm trục và kiểm tra xem phần còn lại của mảng có thể được chia làm hai hay không (sử dụng giao điểm và liên kết: trước tiên xóa tất cả các phần tử> a, sau đó thêm lại phần bên phải và kiểm tra xem có phần nào không đã thay đổi).


3

Võng mạc 0.8.2 , 31 byte

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

Hãy thử trực tuyến! Liên kết bao gồm các trường hợp thử nghiệm. Sử dụng thuật toán của @ tsh. Giải trình:

\d+
$*

Chuyển đổi sang unary.

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

Tìm các số nằm giữa hai số giảm dần liên tiếp.

^0

Kiểm tra xem số lượng trận đấu bằng không.


3

Perl 6 , 38 byte

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

Hãy thử trực tuyến!

Giải trình

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

Dùng thử trực tuyến

Cảng của @ nwellnhof's Câu trả lời .

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

Cảm ơn @Laikoni về các đề xuất để làm cho cả hai giải pháp ngắn hơn.

Dùng thử trực tuyến

Giải trình:

  1. lát (sử dụng Scala's span ) mảng sử dụng đầu của mảng làm tiêu chí cắt.
  2. Xác nhận rằng lát đầu tiên của mảng nhỏ hơn đầu và lát thứ hai lớn hơn đầu.
  3. kiểm tra đệ quy rằng mỗi lát cũng thỏa mãn (2)

1
Tôi nghĩ rằng bạn không cần không gian trong val (s,t), truecó thể 1>0và bạn có thể thả s.forall(_<i(0))&vì điều này đã được bảo hiểm bởi span.
Laikoni

1
Bạn có thể gọi hàm %và thả khoảng trống:def%(i:Seq[Int])=
Laikoni

Giải pháp của bạn chứa khai báo của hàm không giống như một số khác. Biểu cảm thuần túy khá ngắn. ;)
Bác sĩ Y Wit

Tôi đã cố gắng chuyển câu trả lời của tsh, nhưng không quản lý để có đủ ngắn. Phiên bả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)}.. Phiên bả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).. Bất kỳ ý tưởng làm thế nào để làm cho những ngắn hơn?
Bác sĩ Y Wit

Thuật toán bằng tiếng Anh đơn giản: cho mỗi phần tử thực hiện kiểm tra với tất cả các cặp phần tử nằm cạnh nhau.
Bác sĩ Y Wit

2

05AB1E , 15 10 byte

ŒεD{3.IÊ}P

Cổng của câu trả lời Jelly của @Lynn .
-5 byte nhờ @Emigna .

Hãy thử trực tuyến hoặc xác minh tất cả các trường hợp thử nghiệm .

Giải thích: "

Œ             # 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
Thế còn ŒεD{3.IÊ}P?
Emigna

1
@Emigna Vâng, điều đó thực sự sẽ dễ dàng hơn rất nhiều ...>.> Cảm ơn! :) (Và có một ngày cuối tuần vui vẻ.)
Kevin Cruijssen

2

Haskell , 41 byte

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

Hãy thử trực tuyến!

Sử dụng quan sát của Lynn rằng nó đủ để kiểm tra rằng không có phần tiếp theo của mid..high..low . Điều này có nghĩa là đối với mỗi phần tử h, danh sách các phần tử tđi sau là một khối phần tử <htheo sau là một khối phần tử >h(cả hai khối có thể trống). Vì vậy, mã kiểm tra rằng sau khi chúng ta bỏ tiền tố của các phần tử <hvào t, các phần tử còn lại là tất cả >h. Việc đệ quy kiểm tra điều này cho từng phần tử ban đầu hcho đến khi danh sách có độ dài 1.

Một sự đơn giản hóa tiềm năng là nó đủ để kiểm tra các mẫu con ở giữa..high, thấp trong đó hai cái cuối cùng liên tiếp. Thật không may, Haskell không có một cách ngắn để trích xuất hai yếu tố cuối cùng, như có thể được thực hiện từ phía trước với khớp mẫu a:b:c. Tôi tìm thấy một giải pháp ngắn hơn để kiểm tra mid, high..low , nhưng điều này không từ chối đầu vào như thế nào [3,1,4,2].

Các trường hợp thử nghiệm được định dạng lấy từ Laikoni .


1

Japt , 14 byte

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

Phiên dịch viên Japt

Đầu ra falsecho BST, truekhông có BST.

Giải trình:

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

Tất cả các phương pháp tiếp cận là việc thực hiện quy tắc được hiển thị bởi 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)

Nếu nó phải là một hàm và không chỉ là một biểu thức thì mỗi dòng phải bắt đầu bằng (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

Vì không có kiểu boolean trong Oracle SQL, truy vấn trả về 1 hoặc 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)

Không thể truy cập phần tử của mảng trong SQL giống như trong PL / SQL - tức là a (i), do đó hàm fđược khai báo trongwith clause cho mục đích đó. Nếu không thì giải pháp sẽ ngắn hơn nhiều.

Những hạn chế khác

  • đưa ra một ngoại lệ cho các mảng ngắn hơn 3 phần tử (thay vì trả về 1)
  • có một giả định rằng powermultiset_by_cardinality duy trì trật tự mặc dù nó không được nêu rõ trong tài liệu

danh sách 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

Xác minh trực tuyến apex.oracle.com

Cập nhật

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 (không tính các ký tự khoảng trắng); 923 byte (bao gồm cả khoảng trắng)

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

Phiên bản dễ đọc của chương trình dưới đây:

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

Phương thức chính trong chương trình này đọc danh sách các số (được cho là) ​​một giao dịch đặt hàng trước hợp pháp.

Hàm insert_root được gọi là chèn các số nguyên vào cây tìm kiếm nhị phân trong đó các nút trước đó chứa các giá trị nhỏ hơn và các nút tiếp theo chứa các giá trị int lớn hơn.

Hàm preorder (root) đi ngang qua cây trong một đường ngang preorder và đồng thời nối từng số nguyên mà thuật toán đi qua với test_list mảng int .

Vòng lặp while cuối cùng kiểm tra nếu mỗi giá trị int trong danh sách stdin và các giá trị trong test_list tương đương tại mỗi chỉ mục. Nếu có một phần tử danh sách từ stdin không khớp với phần tử tương ứng trong test_list tại chỉ mục tương ứng, hàm main trả về 0. Khác phương thức chính trả về 1 .

Để xác định chính nào được trả về, hãy nhập echo $ status vào thiết bị đầu cuối bash. BASH sẽ in ra 1 hoặc 0.


2
Điểm của bạn là khoảng trắng đếm.
Phù thủy lúa mì
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.