"Lazy Sort" Uygulaması


44

Numaraların bir listesini yapmam gerekiyor, ama çok tembelim. Tüm sayıları sıralayana kadar etrafındaki sayıları nasıl değiştireceğinizi anlamak gerçekten zor, bu yüzden yeni listenin sıralanacağını garanti edecek kendi algoritmamla geldim. İşte nasıl çalışıyor:

N büyüklüğünün bir listesi için N-1 yinelemeye ihtiyacımız olacak . Her yinelemede,

  • N'ci sayıların N + 1'lik sayıdan küçük olup olmadığını kontrol edin . Öyleyse, bu iki sayı zaten sıralanır ve bu yinelemeyi atlayabiliriz.

  • Değilse, bu iki sayı sıralanana kadar ilk N sayısını sürekli olarak azaltmanız gerekir .

Somut bir örnek alalım. Diyelim ki girdi

10 5 7 6 1

İlk yinelemede, 10 ve 5'i karşılaştıracağız. 10, 5'ten büyüktür, bu nedenle daha küçük olana kadar azaltırız:

4 5 7 6 1

Şimdi 5 ile 7'yi karşılaştırıyoruz. 5 7'den daha küçük, bu nedenle bu yinelemede bir şey yapmamıza gerek yok. Öyleyse sonrakine gidip 7 ile 6'yı karşılaştırırız. 7 6'dan büyüktür, bu yüzden ilk üç sayıyı 6'dan küçük olana dek azaltır ve şunu elde ederiz:

2 3 5 6 1

Şimdi 6 ile 1'i karşılaştırıyoruz. Yine, 6 1'den büyük, bu yüzden ilk dört sayıyı 1'den küçük olana kadar düşürdük ve şunu elde ettik:

-4 -3 -1 0 1

Ve biz bitti! Şimdi listemiz mükemmel bir sıralama düzeninde. Ve, işleri daha da iyi hale getirmek için, sadece N-1 listesini tekrarlamak zorunda kaldık , bu yüzden bu algoritma O (N-1) zamanındaki listeleri sıralar, ki bu da en hızlı algoritma olduğundan eminim.

Bugün için zorlu göreviniz bu Tembel Sıralama'yı uygulamak. Programınıza veya fonksiyonunuza, istediğiniz standart formatta bir tamsayı dizisi verilecek ve bu tembel sıralama işlemini gerçekleştirmeli ve yeni "sıralı" listeye geri dönmelisiniz . Dizi asla boş olmaz veya tamsayı içermez.

İşte bazı örnekler:

Input: 10 5 7 6 1
Output: -4 -3 -1 0 1

Input: 3 2 1
Output: -1 0 1

Input: 1 2 3
Output: 1 2 3

Input: 19
Output: 19

Input: 1 1 1 1 1 1 1 1 1 
Output: -7 -6 -5 -4 -3 -2 -1 0 1 

Input: 5 7 11 6 16 2 9 16 6 16
Output: -27 -25 -21 -20 -10 -9 -2 5 6 16

Input: -8 17 9 7
Output: -20 5 6 7

Her zaman olduğu gibi, bu , bu yüzden mümkün olan en kısa programı yazın!


¹ Bu, kulağa nasıl geldiği anlamına gelmez, ancak teknik olarak doğrudur.

² Şaka yapıyorum, lütfen benden nefret etme


6
Ben bu şekilde yaparsan tembel olmadığını düşünüyorum
Jörg Hülsermann

4
@ JörgHülsermann pek çok tamsayı çok ağır ... tam olarak böyle bir ağırlık taşıyabilecek durumda değil, sadece en iyi şeyleri çıkaracak kadar iyi değil
Erik Outgolfer

21
<sarcasm>Bu sıralama algoritması gerçekte O(N^2)zaman zaman karmaşıklığını hala sürdürmektedir, çünkü listedeki önceden erişilmiş tüm öğeleri gözden geçirmek için onları azaltmak zorundasınız. Listeyi geriye doğru atmanızı ve adım başına yalnızca bir sayıyı azaltmanızı öneririm . Bu size gerçek bir O(N)karmaşıklık verecektir ! </sarcasm>
Value Ink

1
@ValueInk O(n^2)bellek erişimleri açısından, ancak O(n)karşılaştırmalar için değil mi?
Cole Johnson,

7
@ColeJohnson teknik olarak evet, ancak zaman karmaşıklığının algoritmanın tüm adımlarını göz önünde bulundurması gerekiyor. Her yinelemede önceki tüm endeksleri yinelemelisiniz, bu yüzden hala çıkıyor O(N^2).
Value Ink

Yanıtlar:


12

Jelly ,  14 12 11  9 bayt

ETHproductions sayesinde -2 bayt (minimum dyad kullanın «)

I’«0Ṛ+\Ṛ+

Bir tamsayı listelerini alıp geri veren monadik bir bağlantı.

Çevrimiçi deneyin! veya test odasına bakın .

Gerçekten bunun Lazy ™ olduğunu sanmıyorum!

Nasıl?

I’«0Ṛ+\Ṛ+ - Link: list of integers, a              e.g. [ 8, 3, 3, 4, 6, 2]
I         - increments between consecutive items of a   [-5, 0, 1, 2,-4 ]
 ’        - decrement (vectorises)                      [-6,-1, 0, 1,-5 ]
   0      - literal 0
  «       - minimum of decremented increments and zero  [-6,-1, 0, 0,-5 ]
    Ṛ     - reverse                                     [-5, 0, 0,-1,-6 ]
      \   - cumulative reduce with:
     +    -   addition                                  [-5,-5,-5,-6,-12]
       Ṛ  - reverse                                     [-12,-6,-5,-5,-5]
        + - addition (with a)                           [-4,-3,-2,-1, 1, 2]


8

JavaScript (ES6), 61 bayt

a=>a.map((b,i)=>a=(b-=a[i+1])>0?a.map(c=>i--<0?c:c-b-1):a)&&a

Test durumları


7

Jöle , 12 bayt

I»1U
0ị;Ç_\U

Çevrimiçi deneyin!

Nasıl çalışır

I»1U  Helper link. Argument: l (list of integers)
I     Compute the increments (difference between items) of l.
 »1   For each item n, take the maximum of n and 1.
   U  Reverse.

0ị;Ç_\U  Main link. Argument: l (list of integers)
   Ç     Call the helper link with argument l.
  ;      Concatenate this with
0ị       the 0th last item of the (1-indexed) l. (Can't use Ṫ because it modifies l)
    _\   Cumulatively reduce the result by subtraction.
      U  Reverse.

Oyunda temel fikir şudur: Giriş ve çıkış dizilerini ters çevirirseniz, çıkış basitçe 0 veya daha büyük her delta olan -1 ile değiştirilen girişdir. Örneğin:

[10,  5,  7,  6,  1]   input
[ 1,  6,  7,  5, 10]   reverse
[   5,  1, -2,  5  ]   deltas
[  -1, -1, -2, -1  ]   min(deltas, -1)
[ 1, -1, -2, -1, -1]   reverse and concat the last item of the original
[ 1,  0, -2, -3, -4]   re-apply deltas
[-4, -3, -2,  0,  1]   reverse

5

k, 20 bayt

{x-|+\0,1_0|1+-':|x}

Çevrimiçi deneyin.

Açıklama:

{                  } /function, x is input
                 |x  /reverse x
              -':    /difference between every element
            1+       /add one to each difference
          0|         /make minimum difference be 0
      0,1_           /swap first difference with a 0
    +\               /cumulative sum
   |                 /reverse again
 x-                  /subtract from x

4

Haskell, 56 bayt

a#(x:y:z)=map(+min(y-x-1)0)(a++[x])#(y:z)
a#x=a++x
([]#)

Çevrimiçi deneyin!

Listenin ilk bölümünü parametrede tut a. Her adımda bir sonraki elemanı xsonuna ekleyiniz ave a'nın tüm elemanlarını en az (y-x-1)ve 0.


4

Python , 54 bayt

f=lambda a,*r:r and[f(*r)[0]-max(r[0]-a,1)]+f(*r)or[a]

Çevrimiçi deneyin!

Sıçramış girişi alır f(1,2,3). Bir liste çıkarır. Üstel zaman kullanır.


3

C #, 76 bayt

a=>{for(int d=0,i=a.Length-1;i>0;a[--i]-=d)d=a[i-1]-d<a[i]?d:a[i-1]-a[i]+1;}

Bu, listeyi yerinde değiştirir. Listede geriye doğru gider ve her numaraya uygulanacak toplam deltayı tutar.


2

JavaScript (ES6), 59 bayt

f=([n,...a],p=a[0]-n)=>a+a?[(a=f(a))[0]-(p>1?p:1),...a]:[n]

Vay. Bir JS çözümü yazmak üzereydim ama sonra bunu gördüm. Spread operatörünü bu parametrelerde kullanmayı düşünmedim
andrewarchi

Sen kapalı bırakabilirsiniz f=JS iki bayt kaydetmek için cevaplar için
andrewarchi

@ andrewarchi Teşekkürler, fakat bu özel fonksiyonun kendisini çağırması gerekir ( f(a)) bu yüzden hala ismini gerektirir.
ETHProductions

Özyineli olduğunu unuttum
andrewarchi

2

Brain-Flak , 153 bayt

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

Çevrimiçi deneyin!

Bu bayrak +1için de geçerlidir -r.

#While True
{

    #Push the last value left in the array minus the counter onto the alternate stack
    (({})<>[({})])

    #Put the counter back on top of the alternate stack
    (({}({}))[({}[{}])])

    #Toggle
    <>

    #Find the difference between the last two inputs left on the array
    (([{}]({})))

    #Greater than or equal to 0?
    ([({}<(())>)](<>)){({}())<>}{}{((<{}>))<>{}}{}<>{}

    #If So:
    {

      #Pop the truthy/falsy value
      {}

      #Increment the counter by the difference between elements +1
      ({}<>{}())

      #Push two falsys
      ((<>))

    #Endwhile
    }

    #Pop the two falsys
    {}{}

#Endwhile
}

#Pop the falsy

{}

#Toggle back
<>

#Pop the counter

#Reverse the stack
{}
([]){{}({}<>)<>([])}<>

2

R, 56 bayt

function(s){s-c(rev(cumsum(rev(pmax(0,-diff(s)+1)))),0)}


1
güzel kullanımı, diffnasıl çalışacağını anlamaya çalışıyordum ... Bu arada, işlev gövdesinin etrafındaki parantezlerden -2 baytlık kurtulabilirsiniz, ancak daha iyisi, s=scan()işlev yerine kullanabilirsiniz Birkaç bayt daha tasarruf etmek için Diğer kişilerin bu kodun tüm sınama durumlarında çalıştığını doğrulayabilmesi için Çevrimiçi olarak denemek için bir bağlantı eklerseniz çok iyi olur .
Giuseppe,

Telaşa gerek yok! hepimiz bir yerden başlıyoruz :)
Giuseppe

1

JavaScript (ES6), 68 bayt

a=>a.map((v,i)=>(d=v-o[i+1]+1)>1?o=o.map((v,j)=>j>i?v:v-d):0,o=a)&&o

Giriş ve çıkış bir tamsayı dizisidir.

Test Parçacığı

f=
a=>a.map((v,i)=>(d=v-o[i+1]+1)>1?o=o.map((v,j)=>j>i?v:v-d):0,o=a)&&o
<input id=I oninput="O.value=f(this.value.split` `.map(x=>+x)).join` `">
<input id=O disabled>


1

JavaScript (ES6), 50 bayt

f=a=>(b=[...a]).some((_,i)=>a[i]-->=a[i+1])?f(a):b

Açıklama:

Bu, önce diziyi klonlayan, sonra bir öğe dizideki bir sonraki öğeye eşit veya daha büyük olana kadar tüm değerleri azaltan özyinelemeli bir çözümdür.

İşlev, herhangi bir eleman arızalı olduğu sürece kendisini çağırır. Öğeler nihayet sıralandığında, klon döndürülür. (Dizinin kendisini döndüremeyiz, çünkü some()yöntem tüm öğeleri azaltıp hepsini -1'e düşürürdü.)

Test durumları:

f=a=>(b=[...a]).some((_,i)=>a[i]-->=a[i+1])?f(a):b

console.log(f([10,5,7,6,1])+'');
console.log(f([1,1,1,1,1,1,1,1,1])+'');
console.log(f([5,7,11,6,16,2,9,16,6,16])+'');
console.log(f([19])+'');
console.log(f([-8,17,9,7])+'');
console.log(f([1,2,3,4,5,6,7])+'');


1

SWI-Prolog, 194 bayt

:-use_module(library(clpfd)).
f([],[],_,_).
f([A|B],[M|N],P,D):-A#=M-D-E,A#<P,abs(M,S),T#=S+1,E in 0..T,label([E]),f(B,N,A,D+E).
l([],[]).
l(A,B):-reverse(Z,B),f([X|Y],Z,X+1,0),reverse(A,[X|Y]).

Burada çevrimiçi deneyebilirsiniz: http://swish.swi-prolog.org/p/LazySort.pl

Sen sor l(L, [10,5,7,6,1])., "L Bu listenin tembel sıralı versiyonu L, için çözmek" diyor hangi.

İki fonksiyon:

  • lazysorted (A, B) - eğer hem boş listeler ise, hem de boş listeler varsa A'nın B'nin Lazysorted versiyonunu belirtir, ya da A'yı B'nin tersine çevirerek elde edip edemeyeceğini, listeyi dolaşmak ve bir akümülatörle çıkarma yapmak için bir yardımcı işlev çağırarak elde edilebileceğini belirtir. her değeri öncekinden daha düşük bir değere itmek ve bunun sonucunu doğru yöne geri döndürmek.
  • fyardımcı iki listeyle eşleşir, listedeki önceki sayının değeri ve yuvarlanan bir fark akümülatörü ve mevcut liste konumunun yeni değeri olan asıl değer olan eksi fark akümülatörünü çözer, isteğe bağlı olarak bunu zorlamak için gereken yeni bir değer listedeki önceki sayının altındaki değer ve listenin fkuyruğu için şimdi artan fark akümülatör ile yinelemeli olarak çözülmelidir.

Swish'teki test davalarının ekran görüntüsü:

Swish'te çalışan test durumlarını gösteren resim


0

JavaScript (ES6), 61 bayt

a=>a.reduceRight((r,e)=>[e-(d=(c=e-r[0]+1)>d?c:d),...r],d=[])

En kısa çözüm değil, ancak kullanma fırsatını geçemedim reduceRight.


0

C # (.NET Core) , 89 88 86 79 bayt

  • Biraz farklı bir yaklaşımla sadece 1 byte kurtarıldı.
  • forS bir basitleştirme ile başka 2 bayt kaydedildi .
  • VisualMelon'un muhteşem golf becerisi sayesinde 7 byte tasarruf sağladı.
a=>{for(int i=0,j,k;++i<a.Length;)for(k=a[i-1]-a[j=i]+1;--j>=0;)a[j]-=k>0?k:0;}

Çevrimiçi deneyin!

İlk forolarak dizi boyunca yinelenir, sonra azalmayı hesaplar ve ikinci olarak forgerektiğinde elemanları ipozisyona kadar düşürür.

Yenisini döndürmek yerine sadece orijinal diziyi değiştirmek geçerli midir (yine de kurallara alışmak)?


Evet, orijinal diziyi değiştirmek tamamen iyi. :)
DJMcMayhem

4
@DJMcMayhem teşekkürler, yeni bir tane oluşturmak için çok tembel hissettim. :)
Charlie
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.