Làm thế nào khó khăn tôi có thể nghiền nát mảng của tôi?


30

Cho phép xác định quá trình nghiền một mảng số. Trong một lòng, chúng tôi đọc các mảng từ trái sang phải. Nếu tại một điểm chúng ta bắt gặp hai phần tử giống nhau trong một hàng, chúng ta sẽ loại bỏ phần tử thứ nhất và nhân đôi phần tử thứ hai. Ví dụ ở đây là quá trình nghiền mảng sau

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

Phần tử tương tự có thể được thu gọn nhiều lần, ví dụ [1,1,2]trở thành [4]khi bị nghiền nát.

Chúng tôi sẽ gọi một mảng không thể xóa được khi quá trình nghiền mảng đó không thay đổi. Ví dụ [1,2,3]vẫn còn [1,2,3]sau khi bị nghiền nát.

Nhiệm vụ của bạn là lấy một mảng và xác định số lần nghiền cần thiết để làm cho nó không thể xóa được. Bạn chỉ cần hỗ trợ số nguyên trong phạm vi từ 0 đến 2 32 -1

Đây là vì vậy câu trả lời sẽ được tính bằng byte với ít byte hơn.

Các trường hợp thử nghiệm

[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
Nên [1,1,2,4,8]trả lại 1 hay 4?
MooseBoys

2
@ThePirateBay Ok tôi sẽ hạ nó xuống. Nhưng đối với bản ghi tôi nghĩ rằng Javascript khá ngu ngốc trong cách xử lý ints.
Thuật sĩ lúa mì

2
Nếu bạn cố gắng nghiền nát [1 1 1 2], bạn sẽ kết thúc với [2 1 2] nếu bạn làm theo thông số kỹ thuật chính xác như được viết, nhưng bạn có thể kết thúc bằng [1 4] nếu bạn làm điều đó thông minh hơn. Điều gì [1 1 1 2] sẽ dẫn đến?
latias1290

4
@ latias1290. "Trong một cơn say, chúng tôi đọc các mảng từ trái sang phải."

11
Có lẽ nó chỉ là tôi nhưng nó đã cho tôi một giây để tìm ra lý do tại sao 0,0,0,0chỉ là 1. Có thể là một ý tưởng để đề cập rõ ràng ở đâu đó rằng chúng ta đang đếm số lần chúng ta phải lặp qua một mảng để hoàn toàn nghiền nát nó và không , như tôi nghĩ ban đầu, tổng số lần chúng ta nghiền nát 2 số với nhau.
Xù xì

Câu trả lời:


12

lắp ráp x86 (64 bit), 66 65 byte

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

Hướng dẫn chuỗi là hữu ích. Phải sửa lỗi cho từng lỗi trong môi trường 64 bit thì không.

Mã nguồn nhận xét đầy đủ:

.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

Tôi có thể thử làm điều này trong 32-bit, nếu chỉ để giải trí, vì những tiền tố REX đó thực sự đã giết chết tôi.

Chỉnh sửa: xóa một byte bằng cách thay thế lodsq bằng add,% rdx bằng% rax và thu gọn hai cld thành một.



6

Haskell , 66 byte

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)

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

Giải trình

flà một chức năng mà nghiền nát một danh sách. Nó thực hiện lòng như mong muốn trong câu hỏi. glà một hàm đếm số lần nghiền. Nếu f x==x, g x=0nếu không g x=1+g(f x).


1
Cạo sạch một byte bằng cách thay đổi g(f x)thànhg$f x
Cách tiếp

3
@ApproachingDarknessFish Điều đó không hiệu quả vì +có quyền ưu tiên cao hơn$
Wheat Wizard

Ah, xấu của tôi. Thật buồn cười là tôi chưa bao giờ gặp phải lỗi đó trước đây.
Tiếp

5

Nghịch lý (v0.2.10), 16 byte (CP-1252)

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

Hãy thử trực tuyến! / với tiêu đề / chân trang kiểm tra tất cả các trường hợp thử nghiệm

Lấy một danh sách trên ngăn xếp và kết quả là một số trên ngăn xếp.

Thực hiện khá đơn giản, phải khá trung thực. Nghiền danh sách bằng cách bắt đầu với một sentinel -1, lặp qua danh sách, đẩy từng phần tử và thêm nó vào phần tử bên dưới nó nếu chúng bằng nhau. Cuối cùng, chúng tôi cắt -1. Chúng tôi chỉ nghiền các số bằng nhau với nhau và tất cả các số của bài toán là không âm, vì vậy, giá trị -1 sẽ không ảnh hưởng đến quá trình nghiền. Với việc nghiền nát được thực hiện, đó chỉ là vấn đề đếm số lần lặp đến điểm cố định của nó.

Giải trình:

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

Nếu chúng ta có thể giả sử đầu vào là không trống, chúng ta sẽ không cần sentinel và có thể cạo 2 byte: {(\ε=k+x}]}IL(

Một sự thật thú vị khác: chúng tôi chỉ mất 2 byte nếu chúng tôi buộc mình chỉ sử dụng ASCII: {1m\{=k+x}e]1>}IL(


4

JavaScript (ES6), 86 byte

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

Ungolfed và giải thích

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

Xét nghiệm


a.length>ncũng giống như a[n]!=[]._. Trong trường hợp này (vì tất cả các mục trong mảng là các số lớn hơn -1), nó giống như a[n]>-1. Ngoài ra, a[i]==a[++i]&&xlà giống như a[i]-a[++i]||x.
Lu-ca

Tôi nghĩ 1/a[i]cũng hoạt động để tiết kiệm một byte khác.
Neil

4

JavaScript, 67 byte

f=a=>a.map(a=>k[k[d-1]!=a?d++:(a*=z=2,d-1)]=a,k=d=[z=0])&&z&&f(k)+1

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


Tốt đẹp! Tôi nghĩ rằng tôi đã đánh golf này càng thấp càng tốt.
Rick Hitchcock

3

Brain-Flak , 144 byte

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

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

Giải trình

([])                                                                 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

Hàm crush ước tính số lượng các cặp vật phẩm được nghiền nát với nhau:

([][()]){[{}]                                                            ([][()])}    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

Java 8, 120 byte

Một lambda từ List<Long>đến Integer. Danh sách đầu vào phải thực hiện remove(int)(ví dụ ArrayList). Chỉ định cho 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;}

Dùng thử trực tuyến

Lambda

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đếm số lần nghiền cho đến nay, ilà chỉ mục vào danh sách và fcho biết liệu có tiếp tục nghiền danh sách khi việc lặp lại kết thúc hay không. Bên trong các vòng, mỗi cặp liền kề được so sánh. iđược tăng vô điều kiện, do đó, nếu một phần tử được loại bỏ bằng cách nghiền, itrước tiên hãy giảm dần để hủy bỏ phần tăng. Các yếu tố cũ được loại bỏ khỏi danh sách.

Lời cảm ơn

  • Sửa lỗi nhờ Olivier Grégoire: kiểm tra đẳng thức đóng hộp

Không hoạt động khi lâu không nhấn valueOfbộ đệm. Ví dụ : {128L, 128L}. Đó là bởi vì l.get(i)==l.get(i-1), mà nên được thay thế bởi l.get(i).equals(l.get(i-1)).
Olivier Grégoire

Wow, ngượng ngùng ... may mắn l.get(i)-l.get(i-1)==0sẽ làm việc. Cảm ơn!
Jakob


2

JavaScript (ES6), 70 byte

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)

Giải trình:

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

Các trường hợp thử nghiệm:


1
Hừm .. Có vẻ như chúng tôi đã nghĩ ra ý tưởng khá giống nhau :). Sau khi trả lời câu hỏi của tôi, tôi nhận ra nó rất giống với bạn.

2

Python 2 , 112 110 108 107 105 100 byte

Chỉnh sửa: đã lưu 2 byte bằng cách xóa ortrong câu lệnh return

Chỉnh sửa: đã lưu 2 byte bằng cách có ichỉ mục của phần tử thứ hai trong số hai phần tử được truy cập

Chỉnh sửa: đã lưu 1 byte nhờ @ Mr.Xcoder

Chỉnh sửa: đã lưu 7 byte nhờ @jferard

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)

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


2

JavaScript (ES6), 83 byte

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

Giải thích: Các phần tử được trích xuất đệ quy từ mảng ban đầu và các giá trị duy nhất được thêm vào btrong khi đó clà một cờ để cho biết liệu mảng đã được nghiền thành công hay chưa.


1

J, 54 byte

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

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

Không phải golf tốt nhất của tôi bằng mọi cách. Chắc chắn phải có một cách tốt hơn để chuyển đổi một danh sách với một mục thành nguyên tử.

Giải trình

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

nghiền nát

Điều này nghiền nát một mảng một lần. Nó cần phải được đưa ra mảng ngược lại vì phần chèn của J hoạt động từ phải sang trái (điều mà tôi đã học ngày hôm nay). Điều này không đặc biệt quan trọng, vì tất cả những gì chúng ta cần xuất là số lần chúng ta có thể nghiền nát mảng.

,`(+:@[ , }.@])@.({.@] = [)/
                           /  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.

lần

Điều này khá đơn giản: áp dụng crush cho mảng cho đến khi kết quả của chúng tôi hội tụ, nhưng có một vài vấn đề tôi phải giải quyết với kết quả đó với nhiều mã hơn tôi dự đoán.

Đầu tiên, khi việc nghiền giảm thành một phần tử duy nhất, phần tử đó thực sự nằm trong danh sách một mục (nghĩa là không phải là nguyên tử), do đó, hàm được áp dụng lại dẫn đến vượt quá. Để khắc phục điều này, tôi đã sử dụng một hack mà tôi đã nghĩ ra để giảm một danh sách thành phần duy nhất thành một nguyên tử ".@":(chuyển đổi thành chuỗi và sau đó đánh giá).

Thứ hai, crushlỗi trong danh sách trống. Tôi nghĩ rằng bạn có thể xác định cách một chức năng sẽ hoạt động như thế nào khi nhận đầu vào trống bằng insert ( /), nhưng tôi không thể tìm thấy bất cứ điều gì sau một cái nhìn khó hiểu, vì vậy tôi đang sử dụng một cách giải quyết khác. Cách giải quyết này là để thêm vào _(vô hạn) vào danh sách vì nó sẽ không bao giờ ảnh hưởng đến số lần mảng bị nghiền ( _ > 2^64). Tuy nhiên , điều này dẫn đến một danh sách thành phần duy nhất bao gồm _khi được đưa ra danh sách trống, vì vậy chúng ta cần chuyển đổi thành nguyên tử một lần nữa trước khi nghiền.

<:@# [: ".@":@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 byte

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

Thật kinh khủng, tôi chắc chắn có một cách thông minh hơn.

Số nguyên R thực sự là tất cả nhiều nhất 2^31-1.

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

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.