Dizimi ne kadar zorlayabilirim?


30

Bir sayı dizisini ezme işlemini tanımlayalım. Ezilme içinde diziyi soldan sağa okuruz. Bir noktada aynı elementten iki taneyle karşılaşırsak, ilkini çıkarır ve ikinciyi ikiye katlarız. Örneğin, aşağıdaki diziyi ezme işlemi burada

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

Aynı eleman birçok kez daraltılabilir, örneğin ezildiğinde [1,1,2]olur [4].

Bu diziyi ezme işlemi onu değiştirmezse, ezilmeyen diziyi çağırırız. Mesela [1,2,3], [1,2,3]ezilmeden sonra hala .

Göreviniz bir dizi almak ve onu kırılmaz hale getirmek için gereken ezme sayısını belirlemek. Yalnızca 0 - 2 32 -1 aralığındaki destek tam sayılarına ihtiyacınız var.

Bu olduğundan, cevaplar daha az byte'ın daha iyi olmasıyla byte olarak puanlanacak.

Test Kılıfları

[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
Should [1,1,2,4,8]1 veya 4 dönmek?
MooseBoys,

2
@ ThePirateBay Tamam, düşüreceğim. Ancak bu kayıt için Javascript'in ints işleyiş biçiminde oldukça salak olduğunu düşünüyorum.
Buğday Sihirbazı

2
Eğer [1 1 1 2] 'yi ezmeye çalıştıysanız, tam olarak yazıldığı gibi spesifikasyonu takip ederseniz, [2 1 2] ile bitirdiniz, ancak daha zekice yaparsanız [1 4] ile bitirdiniz. [1 1 1 2] neyle sonuçlanmalı?
latias1290

4
@ latias1290. "Ezilme içinde diziyi soldan sağa okuruz."

11
Belki de sadece benim ama neden 0,0,0,0sadece olduğunu anlamak için bir saniye sürdü 1. Açıkça biz onu ezmek ve tam bir dizide aracılığıyla biz döngü vardır kaç kez sayıyorsanız yere belirtmeyi O bir fikir olabilir değil Başlangıçta düşündüğümüz gibi, toplam kaç kez birlikte 2 numara ezmek.
Shaggy

Yanıtlar:


12

x86 düzeneği (64 bit), 66 65 bayt

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

Dize talimatları yardımcı oldu. 64-bit bir ortamda tek tek hataları düzeltmek zorunda kalmak yoktu.

Tamamen yorumlanmış kaynak kodu:

.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

Bunu REX önekleri gerçekten öldürdüğü için sadece eğlence için, 32-bit yapmayı deneyebilirim.

Düzenleme: lodsq 'ı add,% rdx ile% rax ile değiştirip iki cld'nin bir tanesine daraltılmasıyla bir bayt kapalı.



6

Haskell , 66 bayt

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)

Çevrimiçi deneyin!

açıklama

fbir listeyi ezen bir işlevdir. Soruyu tanımlandığı şekilde ezme işlemini gerçekleştirir. gezilme sayısını sayan bir fonksiyondur. Eğer f x==x, g x=0aksi g x=1+g(f x).


1
Değiştirerek byte traş g(f x)etmekg$f x
ApproachingDarknessFish

3
@ YaklaşmaDarknessFish Bu işe yaramaz çünkü çünkü +daha yüksek önceliğe sahip$
Buğday Sihirbazı

Ah, benim hatam. Komik, daha önce hiç bu hatayı yaşamadım.
Yaklaşan

5

Paradok (v0.2.10), 16 bayt (CP-1252)

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

Çevrimiçi deneyin! / tüm test durumlarını kontrol eden üstbilgi / altbilgi ile

Yığında bir liste alır ve yığında bir sayı ile sonuçlanır.

Dürüst olmak gerekirse, oldukça basit bir uygulama. Bir sentinel -1 ile başlayarak, listeyi dolaştırarak, her bir öğeyi iterek ve eşit olduklarında altındaki öğeye ekleyerek bir listeyi eziyor. Sonunda -1'i kestik. Yalnızca eşit sayıları eziyoruz ve tüm problemlerin sayıları olumsuz değil, -1 sentinel kırma işlemini etkilemeyecek. Kırma işleminin gerçekleştirilmesiyle, yalnızca sabit noktadaki yinelemeleri sayma meselesidir.

Açıklama:

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

Girdilerin boş olmadığını varsayabilirsek, nöbetçilere ihtiyacımız olmaz ve 2 bayt tıraş oluruz: {(\ε=k+x}]}IL(

Başka bir eğlenceli gerçek: eğer yalnızca ASCII kullanmaya zorlarsak 2 bayt kaybederiz: {1m\{=k+x}e]1>}IL(


4

JavaScript (ES6), 86 bayt

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 ve Açıklaması

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

Testler


a.length>naynıdır a[n]!=[]._. Bu durumda (dizideki tüm öğeler -1'den büyük sayılar olduğundan), aynıdır a[n]>-1. Ayrıca, a[i]==a[++i]&&xaynıdır a[i]-a[++i]||x.
Luke,

Sanırım 1/a[i]başka bir bayttan tasarruf etmek için de çalışıyor.
Neil,

4

JavaScript, 67 bayt

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

Çevrimiçi deneyin!


Güzel! Bunu olabildiğince düşük kullandığımı sanıyordum.
Rick Hitchcock

3

Brain-Flak , 144 bayt

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

Çevrimiçi deneyin!

açıklama

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

Crush işlevi, birlikte ezilmiş öğe çiftlerinin sayısını değerlendirir:

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

A lambda List<Long>için Integer. Giriş listesi uygulanmalıdır remove(int)(örn. ArrayList). Atama 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;}

Çevrimiçi Deneyin

Ungolfed 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şu ana kadarki çarpma sayısını sayar, iendeks listeye girer ve fbir yineleme tamamlandığında listeyi ezmeye devam edip etmeyeceğini gösterir. Halkaların içinde, her bitişik çift karşılaştırılır. ikoşulsuz bir şekilde artırılır, bu nedenle eğer bir eleman ezilme yoluyla çıkarılırsa, iilk önce artışı iptal etmek için azaltılır. Eski eleman listeden çıkarıldı.

Teşekkür

  • Olivier Grégoire sayesinde bugfix: kutulu eşitlik testi

Uzun süreler valueOfönbelleğe çarpmadığında çalışmaz . Örnek: {128L, 128L}. Bu l.get(i)==l.get(i-1), değiştirilmesi gereken nedeniyle l.get(i).equals(l.get(i-1)).
Olivier Grégoire

Vay, utanç verici ... Neyse ki l.get(i)-l.get(i-1)==0çalışacak. Teşekkürler!
Jakob


2

JavaScript (ES6), 70 bayt

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)

Açıklama:

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

Test Durumları:


1
Hm .. Görünüşe göre aynı fikirden geldik :). Golf cevabımdan sonra cevabın seninkine çok benzer olduğunu anladım.

2

Python 2 , 112 110 108 107 105 100 bayt

Düzenleme:or return ifadesini kaldırarak 2 bayt kaydedildi

Düzenleme:i erişilmesi gereken iki öğenin saniyesinin indeksi olarak kaydedilerek 2 bayt kaydedildi

Düzenleme: @ Mr.Xcoder sayesinde 1 bayt kaydedildi

Düzenleme: @ jferard sayesinde 7 bayt kaydedildi

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)

Çevrimiçi deneyin!


2

JavaScript (ES6), 83 bayt

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

Açıklama: Elemanlar orijinal diziden tekrarlı olarak çıkarılır ve dizinin başarılı bir şekilde ezilmiş olup olmadığını gösteren bir işaret bise benzersiz değerler eklenir c.


1

J, 54 bayt

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

Çevrimiçi deneyin!

Hiçbir şekilde en iyi golf benim değil. Elbette bir maddeyi içeren bir listeyi bir atoma dönüştürmenin daha iyi bir yolu olmalı.

açıklama

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

ezmek

Bu bir kez bir dizi eziyor. J'in eki sağdan sola çalıştığından (bugün öğrendiğim bir şey) dizinin tersine verilmesi gerekir . Bu özellikle önemli değil çünkü çıktıya ihtiyacımız olan tek şey diziyi kırabildiğimiz sayı.

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

zamanlar

Bu oldukça basittir: sonuç birbirine yaklaşıncaya kadar diziye ezilme uygulayın, ancak beklediğimden çok daha fazla kodla sonuçlandırmam gereken birkaç sorun var.

Birincisi, kırma işlemi tek bir elemana indirgendiğinde, bu eleman aslında bir ürün listesindedir (yani adsızdır), bu nedenle fonksiyon tekrar sayıma neden olacak şekilde uygulanır . Bunu düzeltmek için tek bir eleman listesini ".@":(dizgiye dönüştür ve sonra değerlendir) bir atoma indirgemek için bulduğum bir hack kullandım .

İkincisi, crushboş listedeki hatalar. Ben düşünüyorum Eğer bir fonksiyon ekleme (boş girişinin alınması üzerine nasıl davranması gerektiğini tanımlayabilirsiniz /), ama başka bir çözüm kullanıyorum bu yüzden, bir bakıştan sonra bir şey bulamadık. Bu geçici çözüm, _dizinin ezilme sayısını asla etkilemeyeceğinden listeye (sonsuz) ön hazırlık yapmaktır _ > 2^64. Bununla birlikte , bu _, boş liste verildiğinde oluşan tek bir öğe listesinde sonuçlanır, bu yüzden ezmeden önce tekrar bir atoma dönüştürmemiz gerekir .

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

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

Korkunç, daha akıllıca bir yol olduğuna eminim.

R tamsayıları aslında en fazla 2^31-1.

Çevrimiçi deneyin!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.