어레이를 얼마나 세게 분쇄 할 수 있습니까?


30

숫자 배열을 분쇄하는 과정을 정의 할 수 있습니다. 호감에서 우리는 배열을 왼쪽에서 오른쪽으로 읽습니다. 한 지점에서 같은 요소 중 두 개가 연속으로 나타나면 첫 번째 요소를 제거하고 두 번째 요소를 두 배로 늘립니다. 예를 들어 다음은 다음 배열을 분쇄하는 과정입니다.

[5,2,2,3]
 ^
[5,2,2,3]
   ^
[5,2,2,3]
     ^
[5,4,3]
   ^
[5,4,3]
     ^

이 예에서 동일 요소는 여러 번 축소 가능 [1,1,2]하게 [4]분쇄 할 때.

해당 배열을 분쇄하는 과정에서 배열을 변경하지 않으면 배열을 분쇄 불가능이라고합니다. 예를 들어 [1,2,3]여전히 [1,2,3]짓 눌린 후입니다.

당신의 임무는 배열을하고 그것을 분쇄 할 수없는 분쇄의 수를 결정하는 것입니다. 당신은의 범위에 정수 지원 필요는 02 32 -1

이것은 이므로 바이트 수가 적을수록 답이 바이트로 표시됩니다.

테스트 사례

[1] -> 0
[1,1] -> 1
[2,1,1] -> 2
[4,2,1,1] -> 3
[2,2,2,1,1] -> 3
[0,0,0,0] -> 1
[4,0,0,0,4] -> 1
[4,0,0,0,0,4] -> 1
[] -> 0

5
[1,1,2,4,8]1 또는 4를 반환 해야합니까 ?
MooseBoys

2
@ThePirateBay Ok 그것을 낮추겠습니다. 그러나 기록을 위해 Javascript는 int를 처리하는 방식이 다소 바보라고 생각합니다.
밀 마법사

2
만약 당신이 [1 1 1 2]를 으깨려고한다면, 당신이 작성한대로 정확하게 스펙을 따른다면 [2 1 2]로 끝나게되지만보다 지능적으로하면 [1 4]로 끝날 수 있습니다. [1 1 1 2]의 결과는 무엇입니까?
latias1290

4
@ latias1290. "반복해서 우리는 배열을 왼쪽에서 오른쪽으로 읽습니다."

11
어쩌면 그것은 단지 나이지만 왜 그런지 알아내는 데 잠시 시간 0,0,0,0이 걸렸습니다 1. 명시 적으로 우리가 호감 완전히에 배열을 통해 우리는 루프가 횟수를 계산하고 어딘가에 언급에 그것은 생각 될 수 없는 내가 처음에 생각했던, 총 횟수는 우리가 함께이 개 숫자를 분쇄.
Shaggy

답변:


12

x86 어셈블리 (64 비트), 66 65 바이트

31 c0 57 59 56 51 56 5f 4d 31 c0 48 83 c6 08 48
83 e9 01 76 1b fc f2 48 a7 75 15 48 d1 67 f8 51
56 57 f3 48 a5 5f 5e 59 fd 48 a7 49 ff c0 eb e5
59 5e 4c 29 c1 48 ff c2 4d 85 c0 75 c7 48 ff c8
c3

문자열 지침이 도움이되었습니다. 64 비트 환경에서 일대일 오류를 수정해야하는 것은 아닙니다.

주석이 달린 소스 코드 :

.globl crush
crush:
/* return value */
xor %eax, %eax
/* save our length in rcx */
push %rdi
pop %rcx
pass:
/* save the start of the string and the length */
push %rsi
push %rcx
/* this is the loop */
/* first copy source to dest */
push %rsi
pop %rdi
/* and zero a variable to record the number of squashes we make this pass */
xor %r8, %r8
/* increment source, and decrement ecx */
add $8,%rsi
sub $1,%rcx
/* if ecx is zero or -1, we're done (we can't depend on the code to take care of this
automatically since dec will leave the zero flag set and cmpsq won't change it) */
jbe endpass
compare:
/* make sure we're going forward */
cld
/* compare our two values until we find two that are the same */
repne cmpsq
/* if we reach here, we either found the end of the string, or
we found two values that are the same. check the zero flag to
find out which */
jne endpass
/* okay, so we found two values that are the same. what we need
to do is double the previous value of the destination, and then
shift everything leftwards once */
shlq $1, -8(%rdi)
/* easiest way to shift leftwards is rep movsq, especially since
our ecx is already right. we just need to save it and the rsi/rdi */
push %rcx
push %rsi
push %rdi
rep movsq
pop %rdi
pop %rsi
pop %rcx
/* problem: edi and esi are now one farther than they should be,
since we can squash this dest with a different source. consequently
we need to put them back where they were. */
std
cmpsq
/* we don't need to put ecx back since the list is now one shorter
than it was. */
/* finally, mark that we made a squash */
inc %r8
/* okay, once we've reached this point, we should have:
 edi and esi: next two values to compare
 ecx: number of comparisons left
so we just jump back to our comparison operation */
jmp compare
endpass:
/* we reached the end of the string. retrieve our old ecx and esi */
pop %rcx
pop %rsi
/* rsi is accurate, but rcx is not. we need to subtract the number of squashes
that we made this pass. */
sub %r8, %rcx
/* record that we performed a pass */
inc %rax
/* if we did make any squashes, we need to perform another pass */
test %r8, %r8
jnz pass
/* we reached the end; we've made as many passes as we can.
decrement our pass counter since we counted one too many */
dec %rax
/* and finally return it */
ret

REX 접두사가 실제로 나를 죽였 기 때문에 재미 만 있다면 32 비트로 이것을 시도 할 수 있습니다.

편집 : lodsq를 add, % rdx를 % rax로 바꾸고 두 cld를 하나로 축소하여 1 바이트를 줄였습니다.



6

하스켈 , 66 바이트

f(a:b:x)|a==b=f$a+a:x|1>0=a:f(b:x)
f x=x
g x|f x==x=0|1>0=1+g(f x)

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

설명

f목록을 분쇄하는 기능입니다. 그것은 질문에 설명 된대로 호감을 수행합니다. g호감 횟수를 계산하는 기능입니다. 만약 f x==x, g x=0그렇지 g x=1+g(f x).


1
g(f x)g$f x
ApproachingDarknessFish

3
@ApproachingDarknessFish +우선 순위가 높기 때문에 작동하지 않습니다$
Wheat Wizard

아, 내 나쁜. 전에는 그 오류가 발생하지 않은 것이 재미 있습니다.
ApproachingDarknessFish 1

5

Paradoc (v0.2.10), 16 바이트 (CP-1252)

{—1\ε=k+x}]»}IL(

온라인으로 사용해보십시오! / 모든 테스트 사례 를 확인하는 머리글 / 바닥 글 포함

스택에서 목록을 가져와 스택에 숫자를 만듭니다.

매우 솔직한 구현, 매우 간단한 구현. 센티넬 -1로 시작하여 목록을 반복하고 각 요소를 밀어 넣고 동일하면 그 아래에 요소를 추가하여 목록을 크러시합니다. 결국 우리는 -1을 차단했습니다. 우리는 같은 수를 함께 분쇄하고 모든 문제의 숫자는 음이 아니므로 -1 센티넬은 분쇄 과정에 영향을 미치지 않습니다. 크 러싱이 구현 된 경우 고정 된 지점까지 반복을 계산하면됩니다.

설명:

{            }I  .. Iterate this block: repeatedly apply it until a fixed
                 .. point is reached, and collect all intermediate results
 —1              ..   Push -1 (note that that's an em dash)
   \             ..   Swap it under the current list of numbers
    ε    }       ..   Execute this block for each element in the list:
     =           ..     Check if it's equal to the next element on the stack...
      k          ..       ... while keeping (i.e. not popping either of) them
       +         ..     Add the top two elements of the stack...
        x        ..       ... that many times (so, do add them if they were
                 ..       equal, and don't add them if they weren't)
          ]      ..   Collect all elements pushed inside the block that
                 ..     we're iterating into a list
           »     ..   Tail: take all but the first element (gets rid of the -1)
              L  .. Compute the length of the number of intermediate results
               ( .. Subtract 1

입력이 비어 있지 않다고 가정하면 센티넬이 필요하지 않고 2 바이트를 면도 할 수 있습니다. {(\ε=k+x}]}IL(

또 다른 재미있는 사실 : ASCII 만 사용하도록 강요하면 2 바이트 만 손실됩니다. {1m\{=k+x}e]1>}IL(


4

자바 스크립트 (ES6), 86 바이트

f=a=>a.length>eval("for(i=0;a[i]>-1;)a[i]==a[++i]&&a.splice(--i,2,a[i]*2);i")?1+f(a):0

언 골프 및 설명

f=a=>                           // function taking array a
    a.length > eval("           // if a.length > the result of the following...
        for(i=0; a[i]>-1;)      //   loop from 0 until the current value is undefined (which is not > -1)
            a[i] == a[++i] &&   //     if the current value equals the next one...
                a.splice(--i,   //       splice the array at the first index of the pair...
                    2,          //       by replacing 2 items...
                    a[i]*2);    //       with the current item * 2
                                //       this also decrements the counter, which means the current value is now the next
    i")                         //   return the counter, which is new a.length
        ? 1+f(a)                // if that was true, the array was crushed. add 1 and recur with the new array
        : 0                     // otherwise just return 0

테스트


a.length>n와 동일합니다 a[n]!=[]._. 이 경우 (배열의 모든 항목이 -1보다 큰 숫자이므로)와 같습니다 a[n]>-1. 또한와 a[i]==a[++i]&&x동일합니다 a[i]-a[++i]||x.
Luke

1/a[i]다른 바이트를 저장 하는 것도 효과가 있다고 생각 합니다.
Neil


3

Brain-Flak , 144 바이트

([])({<{}>(<(([][()]){[{}]<({}[({})]<(())>){({}<{}>({})<>)((<>))}>{}{{}(<(({}){})>)}{}([][()])})>{()(<{}>)}{}{}<><([]){{}({}<>)<>([])}>{}<>)}<>)

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

설명

([])                                                                 Push stack height (starts main loop if list nonempty)
     {                                                       }       Do while the last iteration involved at least one crush:
      <{}>                                                           Remove crush indicator
           <(...)>                                                   Do a crush iteration
                  {()(<{}>)}                                         Evaluate to 1 if list was changed
                            {}{}                                     Remove zeroes
                                <>                        <>         On other stack:
                                  <([]){{}        ([])}>{}           Do while stack is nonempty:
                                          ({}<>)<>                   Move to first stack
          (                                                 )        Push 1 if crush worked, 0 otherwise
    (                                                         <>)    Push sum of results on other stack and implicitly print

분쇄 기능은 함께 분쇄 된 품목 쌍의 수로 평가됩니다.

([][()]){[{}]                                                            ([][()])}    Do while stack height isn't 1:
              ({}[({})]      )                                                        Calculate difference between top two elements
                       <(())>                                                         Push a 1 below difference
                              {                    }                                  If difference was nonzero (don't crush this pair)
                               ({}    ({})<>)                                         Reconstruct top element and place on other stack
                                  <{}>       ((<>))                                   Push zeros to exit this conditional and skip next
             <                                      >{}                               Evaluate as zero
                                                       {              }{}             If difference was zero (crush this pair):
                                                        {}                            Evaluate as previously pushed 1
                                                          (<(({}){})>)                Double top of stack

3

자바 8, 120 바이트

발 람다 List<Long>Integer. 입력 목록은 구현해야합니다 remove(int)(예 :) ArrayList. 에 할당하십시오 Function<List<Long>, Integer>.

l->{int c=-1,i,f=1;for(;f>0;c++)for(f=i=0;++i<l.size();)if(l.get(i)-l.get(i-1)==0)l.set(i-=f=1,2*l.remove(i));return c;}

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

언 골프 람다

l -> {
    int
        c = -1,
        i,
        f = 1
    ;
    for (; f > 0; c++)
        for (f = i = 0; ++i < l.size(); )
            if (l.get(i) - l.get(i - 1) == 0)
                l.set(i -= f = 1, 2 * l.remove(i));
    return c;
}

c현재까지 크러쉬 수를 세고, i리스트의 인덱스이며 f, 반복이 완료 될 때리스트 크러시를 계속할지 여부를 나타냅니다. 루프 내에서 인접한 각 쌍이 비교됩니다. i무조건 증분되므로 분쇄하여 요소를 제거하면i 먼저 증분을 취소하기 위해 감소합니다. 전자는 목록에서 제거됩니다.

감사의 말

  • 올리비에 그레고리 (Olivier Grégoire)의 버그 수정 : 박스형 동등성 테스트

long이 valueOf캐시에 도달하지 않으면 작동하지 않습니다 . 예 : {128L, 128L}. 때문입니다 . l.get(i)==l.get(i-1)로 교체해야합니다 l.get(i).equals(l.get(i-1)).
Olivier Grégoire

와우, 난처하게 ... 운 좋게 l.get(i)-l.get(i-1)==0작동합니다. 감사!
Jakob


2

자바 스크립트 (ES6), 70 바이트

f=(a,j=m=0,t=[])=>a.map(e=>t[e==t[j-1]?(e*=m=2,j-1):j++]=e)&&m&&1+f(t)

설명:

f=(
  a,                  //the input
  j=m=0,              //j is the index into t; m starts out falsey
  t=[]                //t will hold the crushed array
)=>
  a.map(e=>           //for each element in the array
    t[e==t[j-1] ?     //if the element repeats:
      (e*=m=2,        //... multiply it by two, set m to truthy,
       j-1) :         //... and index the previous element of t.
      j++             //else append to t, and increment its index.
    ]=e               //set this index of t to the current value of e
  ) &&                //map is always truthy
  m &&                //if m is falsey, return 0
  1+f(t)              //else return 1 plus the recurse on t

테스트 사례 :


1
흠 .. 우리는 거의 같은 아이디어를 생각해 냈습니다 :). 골프 내 대답 후 나는 그것이 당신과 매우 유사하다는 것을 깨달았습니다.

2

파이썬 (2) , 112 (110) 108 107 105 100 바이트

편집 :or return 문 을 제거하여 2 바이트 저장

편집 :i 액세스 할 두 요소 중 두 번째 요소의 인덱스로 사용하여 2 바이트를 절약했습니다 .

편집 : @ Mr.Xcoder 덕분에 1 바이트 저장

편집 : @jferard 덕분에 7 바이트 저장

def f(x):
 i=e=1
 while x[i:]:
	if x[~-i]==x[i]:del x[i];i-=1;x[i]*=2;e=2
	i+=1
 return~-e and-~f(x)

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


2

자바 스크립트 (ES6), 83 바이트

f=([x,y,...a],b=[],c)=>1/x?x==y?f([x+y,...a],b,1):f([y,...a],[...b,x],c):c?1+f(b):0

설명 : 원래 배열에서 요소를 재귀 적으로 추출하고 고유 한 값이 추가되는 b반면 c배열은 성공적으로 분쇄되었는지 여부를 나타내는 플래그입니다.


1

J, 54 바이트

[:<:@#[:".@":@(,`(+:@[,}.@])@.({.@]=[))/^:a:@".@":_,|.

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

내 최고의 골프가 아닙니다. 하나의 항목이있는 목록을 원자로 변환하는 더 좋은 방법이 있어야합니다.

설명

crush =. ,`(+:@[ , }.@])@.({.@] = [)/
times =. <:@# [: ".@":@crush^:a:@".@": _ , |.

눌러 부수다

이것은 배열을 한 번 분쇄합니다. J의 삽입은 오른쪽에서 왼쪽으로 작동하기 때문에 배열을 으로 제공해야합니다 (오늘 배운 것). 우리가 출력해야 할 모든 것은 배열을 분쇄 할 수있는 횟수이기 때문에 이것은 중요하지 않습니다.

,`(+:@[ , }.@])@.({.@] = [)/
                           /  Fold/reduce from the right
                  {.@] = [    Head of the running array equals the left argument?
   +:@[ ,                     If so, prepend double the argument to 
          }.@]                the array minus its head
,                             Else, prepend the left argument.

타임스

결과는 수렴 될 때까지 배열에 크러시를 적용하지만 예상보다 훨씬 많은 코드로 처리해야하는 몇 가지 문제가 있습니다.

첫째, 분쇄가 단일 요소로 감소하면 해당 요소는 실제로 하나의 항목 목록에 있으므로 (즉, 비원 자적) 함수가 다시 적용 되어 계산이 많아집니다. 이 문제를 해결하기 위해 단일 원소 목록을 원자로 줄이는 해킹을 사용했습니다.".@": (문자열로 변환 한 다음 평가).

둘째, crush빈 목록에 오류가 있습니다. 내가 생각하는 당신이 기능을 삽입 (빈 입력을 수신에 행동하는 방법을 정의 할 수 있습니다 /)하지만 난 다른 해결 방법을 사용하고, 그래서 나는 대충 살펴 후 아무것도 찾을 수 없습니다. 이 해결 방법은 _배열이 으깨지는 횟수 ( _ > 2^64)에 영향을 미치지 않으므로 목록 앞에 추가 (무한대)하는 것 입니다. 그러나 이로 인해 _빈 목록이 주어지면 단일 요소 목록이 생성 되므로 분쇄하기 전에 원자로 다시 변환해야합니다 .

<:@# [: ".@":@crush^:a:@".@": _ , |.
                                  |.  Reverse input
                              _ ,     Prepend infinity
                        ".@":         Convert single-element list to atom
              crush                   Crush the list and after
        ".@":                         Convert single-element list to atom 
                   ^:a:               until it converges, storing each 
                                      iteration in an array
<:@#                                  Length of the resulting list minus 1


0

R , 142 바이트

f=function(l,r=l,k=0,T=1)"if"(sum(l|1)<2,k,{while(T<sum(r|1))"if"(r[T]-r[T+1],T<-T+1,{r<-r[-T]
r[T]<-2*r[T]})
"if"(all(r==l),k,f(r,r,k+1,1))})

끔찍한, 나는 더 영리한 방법이 있다고 확신합니다.

R 정수는 실제로는 전부 2^31-1입니다.

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

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