이것이 BST 선주문 순회입니까?


21

배경

이진 트리가 그 모든 노드 대부분이 아이들이있는 뿌리 나무입니다.

표시 이진 트리가 그 모든 노드 양의 정수로 표시되는 이진 트리입니다; 또한, 모든 라벨은 서로 다릅니다 .

BST (이진 검색 트리) 각 노드의 레이블이 오른쪽 하위 트리에있는 모든 노드의 레이블에 비해 자사의 왼쪽 하위 트리에있는 모든 노드의 레이블보다 큰, 작은 인 레이블 이진 트리입니다. 예를 들어 다음은 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의 다른 값.

규칙

  • 유효한 제출 , I / O , 허점에 대한 표준 규칙 이 적용됩니다.
  • 이것은 이므로 가장 짧은 솔루션 (바이트)이 이깁니다. 평소와 같이, 골프 언어로 된 엄청나게 짧은 해결책이 선택한 언어로 더 긴 답변을 올리는 것을 방해하지 마십시오.
  • 이것은 규칙이 아니지만 솔루션을 테스트하기위한 링크와 작동 방식에 대한 설명이 포함 된 경우 답변이 더 잘 수신됩니다.

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

예제를 시각적으로 살펴 보려면 이 링크 ( Kevin Cruijssen 제공 )를 확인하십시오 .



모든 정수가 양수라고 가정 할 수 있습니까?
GB

@GB 예. 지금 게시물을 편집하겠습니다.
Delfad0r

답변:


11

자바 스크립트 (Node.js) , 49 바이트

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

온라인으로 사용해보십시오!

배열 경우 는 일부 BST의 사전 주문 순회입니다. 보유.에이0...에이1에이0나는<j<;에이나는<에이j1에이나는<에이j

Arnauld 덕분에 1 바이트를 절약하십시오.


8

젤리 , 7 바이트

ŒPŒ¿€4ḟ

온라인으로 사용해보십시오!

[4]순회를 리턴 합니다 [].

기본적으로 tsh의 알고리즘을 사용합니다. 사전 주문 순회에 대한 "실격"조건은 [mid, high, low] 처럼 보이는 3 가지 요소 의 하위 시퀀스 입니다 . (예 : [20, 30, 10])

순열 목록에 인덱스 4있는 길이의 하위 시퀀스도 동일하게 확인합니다. 모든 순차 목록은 [a 1 … a k cdb]같이 정렬됩니다 . 여기서 a i 는 정렬되고 a i <b <c <d 입니다. (우리가 마지막 세 가지 요소를 보면 그러한 각 목록은 실격 처리되며 각 실격 목록은 분명히이 형식입니다.)

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

증명

사전 주문 순회에는 자격이없는 하위 시퀀스가 ​​없습니다.

기본 사례 : traversal (•) 은 빈 목록입니다. ✓

유도 : traversal (t) is : t.root ++ traversal (t.left) ++ traversal (t.right) .

[a, b, c] 를 이의 하위 시퀀스라고 하자 . 우리는 보여주지 C가 <A <b는 불가능하다.

  • 경우 t.root = a를 다음 <A <B C 필요 C ∈ t.leftB ∈ t.right 때문에 [C A, B] 잘못된 순서이다.
  • 경우 A, B, C ∈ t.left 또는 A, B, C ∈ t.right , 인덕션 가설을 사용한다.
  • 만약 ∈ t.leftC ∈ t.right 다음 > ㄷ .

하위 시퀀스를 규정하지 않은 고유 정수 목록은 BST의 사전 주문 순회입니다.

목록이 비어 있으면 사소한 BST의 순회입니다.

목록이 경우 머리 뒤에 꼬리 :

  • 하자 미만 의 가장 긴 접두사가 될 꼬리 미만 요소의 머리 , 그리고하자 리스트의 나머지합니다.
  • 그런 다음 more [1]> head 및 기타 모든 more [i]head 보다 큽니다 (그렇지 않으면 [head, more [1], more [i]] 는 실격 서브 시퀀스입니다).
  • 같이 Recurse는 : 회전 하고 BST를로.
  • 이제 우리의 목록은

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

    이 트리는 유효한 BST입니다.


1
좋은 증거. 실제로 나는 답변을 게시 할 때 공식을 입증하지 못했습니다. 방금 입력에서 BST를 구성하려고 시도한 후에 올바른 것이라고 느꼈습니다.
tsh

5

자바 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 부울이있는 TIL은로 재 할당 할 수 있습니다 |=. 나는 &=또한 작동 한다고 가정 합니까?
J. Sallé

@ J.Sallé 네는 모두 |=&=바로 가기 등의 작업 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

일치 수가 0인지 확인하십시오.




3

스칼라 ( 68 67 바이트)

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

온라인으로 사용해보십시오

@nwellnhof의 답변 포트 .

스칼라 ( 122103 바이트)

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. span배열의 머리를 슬라이싱 기준으로 사용하여 배열 을 스칼라 사용합니다.
  2. 배열의 첫 번째 슬라이스가 헤드보다 작고 두 번째 슬라이스가 헤드보다 큰지 확인하십시오.
  3. 각 슬라이스가 (2)를 만족하는지 재귀 적으로 확인하십시오.

1
난 당신의 공간이 필요하지 않는 생각 val (s,t), true할 수있다 1>0당신은 삭제할 수 있습니다 s.forall(_<i(0))&이 이미 보험에 가입해야한다로 span.
Laikoni

1
함수를 호출하고 %공간을 삭제할 수 있습니다 .def%(i:Seq[Int])=
Laikoni

귀하의 솔루션에는 다른 것과 달리 함수 선언이 포함되어 있습니다. 순수한 표현은 상당히 짧습니다. ;)
Dr Y Wit

tsh의 답변을 포팅하려고했지만 충분히 짧게 만들지 못했습니다. 버전 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 (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).. 더 짧게 만드는 방법에 대한 아이디어가 있습니까?
Dr Y Wit

일반 영어 알고리즘 : 각 요소에 대해 모든 요소 쌍이 서로 옆에 있는지 확인하십시오.
Dr Y Wit

2

05AB1E , 15 10 바이트

ŒεD{3.IÊ}P

@Lynn 의 젤리 답변 포트 . @Emigna
덕분에 -5 바이트 .

온라인으로 시도 하거나 모든 테스트 사례를 확인하십시오 .

설명 : "

Π            # 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?
Emigna

1
@Emigna 그래, 그건 훨씬 쉬워 질 것이다 ...>.> 감사합니다! :) (그리고 즐거운 주말
보내십시오

2

하스켈 , 41 바이트

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

온라인으로 사용해보십시오!

Lynn의 관찰 을 사용 하여 for mid..high..low 하위 시퀀스가 ​​없는지 확인하면 충분합니다 . 즉 h, 각 요소 에 대해 다음에 t오는 요소 목록은 요소 블록 <h다음에 요소 >h블록이 있습니다 (두 블록 모두 비어있을 수 있음). 그래서, 우리는 요소의 접두사 드롭 한 후 그 코드 검사 <h에가 t, 나머지 요소는 모두 >h. 재귀는 h목록이 길이 1이 될 때까지 각 초기 요소에 대해이를 확인합니다 .

잠재적 인 단순화는 마지막 두 개가 연속되는 곳에서 중간에서 높음, 낮음으로 하위 패턴을 확인하기에 충분하다는 것 입니다. 불행히도, Haskell 's는 패턴 매치로 앞에서 할 수 있듯이 마지막 두 요소를 추출하는 짧은 방법이 없습니다 a:b:c. mid, high..low 를 확인하는 더 짧은 솔루션을 찾았 지만 같은 입력을 거부하지 못했습니다 [3,1,4,2].

Laikoni에서 가져온 형식화 된 테스트 사례 .


1

apt , 14 바이트

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

apt 인터프리터

falseBST 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에는 부울 유형이 없으므로 query는 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)

PL / SQL에서와 같은 방식으로 SQL에서 배열의 요소에 액세스 할 수 없습니다. 즉 a (i)이므로 함수 fwith clause해당 목적 으로 선언되었습니다 . 그렇지 않으면 솔루션이 훨씬 짧았을 것입니다.

다른 한계

  • 1을 반환하는 대신 3 개의 요소보다 짧은 배열에 대해 예외를 throw합니다.
  • 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에 전달하는 각 정수를 동시에 연결합니다 .

최종 while 루프는 stdin 목록의 각 int 값 과 test_list의 각 int 값이 각 인덱스에서 동일한 지 테스트합니다 . stdin 의 list 요소 가 해당 인덱스에서 test_list의 해당 요소와 일치하지 않으면 main 함수 는 0을 리턴합니다. 그렇지 않으면 main 메소드 는 1을 리턴합니다 .

반환 된 메인을 확인하려면 bash 터미널에 echo $ status 를 입력하십시오. BASH는 1 또는 0을 인쇄합니다.


2
당신의 점수는 공백을 세는 것입니다.
밀 마법사
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.