ใช้“ Lazy Sort”


44

ฉันควรจะเรียงลำดับรายการตัวเลข แต่ฉันขี้เกียจสุด ๆ เป็นเรื่องยากมากที่จะหาวิธีสลับตัวเลขทั้งหมดที่อยู่ในลำดับที่เพิ่มขึ้นดังนั้นฉันจึงใช้อัลกอริทึมของตัวเองที่จะรับประกันว่ารายการใหม่จะถูกจัดเรียง¹ นี่คือวิธีการทำงาน:

สำหรับรายการขนาดNเราจะต้องมีการทำซ้ำN-1 ในแต่ละรอบซ้ำ

  • ตรวจสอบว่าหมายเลข N'th นั้นเล็กกว่าN + 1'thหรือไม่ หากเป็นเช่นนั้นตัวเลขทั้งสองนี้จะถูกจัดเรียงไว้แล้วและเราสามารถข้ามการทำซ้ำได้

  • หากไม่ใช่คุณจำเป็นต้องลดจำนวนNหมายเลขแรกอย่างต่อเนื่องจนกว่าตัวเลขทั้งสองนี้จะเป็นไปตามลำดับ

ลองยกตัวอย่างที่เป็นรูปธรรม สมมติว่าอินพุตเป็น

10 5 7 6 1

ในการคำนวณซ้ำครั้งแรกเราจะเปรียบเทียบ 10 และ 5 10 มากกว่า 5 ดังนั้นเราจะลดมันจนกว่ามันจะเล็กกว่า:

4 5 7 6 1

ตอนนี้เราเปรียบเทียบ 5 กับ 7. 5 น้อยกว่า 7 ดังนั้นเราไม่จำเป็นต้องทำอะไรเลยในการทำซ้ำนี้ ดังนั้นเราไปต่อไปและเปรียบเทียบ 7 และ 6 7 มีขนาดใหญ่กว่า 6 ดังนั้นเราจึงลดตัวเลขสามตัวแรกจนกระทั่งมันเล็กกว่า 6 และเราได้สิ่งนี้:

2 3 5 6 1

ตอนนี้เราเปรียบเทียบ 6 และ 1 อีกครั้ง 6 มีขนาดใหญ่กว่า 1 ดังนั้นเราจึงลดตัวเลขสี่ตัวแรกจนกระทั่งมันเล็กกว่า 1 และเราได้สิ่งนี้:

-4 -3 -1 0 1

และเราทำเสร็จแล้ว! ตอนนี้รายการของเราอยู่ในลำดับที่สมบูรณ์แบบ และเพื่อทำให้สิ่งต่าง ๆ ดียิ่งขึ้นเราต้องทำซ้ำผ่านรายการN-1ครั้งดังนั้นอัลกอริทึมนี้จึงเรียงลำดับรายการในเวลาO (N-1)ซึ่งฉันค่อนข้างแน่ใจว่าเป็นอัลกอริทึมที่เร็วที่สุดที่มี²

ความท้าทายของคุณสำหรับวันนี้คือการใช้ Lazy Sort โปรแกรมหรือฟังก์ชั่นของคุณจะได้รับอาร์เรย์จำนวนเต็มในรูปแบบมาตรฐานที่คุณต้องการและคุณจะต้องทำการเรียงลำดับแบบขี้เกียจและส่งกลับรายการ"เรียงลำดับ"ใหม่ อาร์เรย์จะไม่ว่างเปล่าหรือมีจำนวนเต็ม

นี่คือตัวอย่างบางส่วน:

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

และเช่นเคยนี่คือดังนั้นเขียนโปรแกรมที่สั้นที่สุดที่คุณสามารถทำได้!


¹ นี่ไม่ได้หมายความว่ามันหมายถึงอะไร แต่เป็นความจริงทางเทคนิค

² ฉันล้อเล่นได้โปรดอย่าเกลียดฉัน


6
ฉันคิดว่าคุณไม่ขี้เกียจถ้าคุณทำแบบนี้
JörgHülsermann

4
@ JörgHülsermannดีจำนวนเต็มหนักเกินไป ... ไม่ว่าในอารมณ์ที่จะดำเนินการดังกล่าวน้ำหนักดีกว่าที่จะออกเพียงสิ่งด้านบนออก
Erik the Outgolfer

21
<sarcasm>อัลกอริทึมการเรียงลำดับนี้จริง ๆ แล้วยังนาฬิกาในO(N^2)เวลาที่ซับซ้อนเนื่องจากคุณต้องผ่านรายการที่เข้าถึงก่อนหน้านี้ทั้งหมดในรายการเพื่อลดพวกเขา ฉันแนะนำให้ทำรายการย้อนหลังแทนและลดจำนวนเพียงหนึ่งหมายเลขต่อขั้นตอนเท่าที่จำเป็น สิ่งนี้จะให้ความO(N)ซับซ้อนที่แท้จริงแก่คุณ! </sarcasm>
หมึกมูลค่า

1
@ValueInk O(n^2)ในแง่ของการเข้าถึงหน่วยความจำ แต่มันไม่ได้O(n)สำหรับการเปรียบเทียบ?
โคลจอห์นสัน

7
@ColeJohnson ใช่แล้ว แต่ความซับซ้อนของเวลาจำเป็นต้องใช้ทุกขั้นตอนของอัลกอริทึมในการพิจารณา O(N^2)คุณยังมีการย้ำผ่านดัชนีก่อนหน้านี้ทั้งหมดในทุกซ้ำดังนั้นจึงยังคงออกมา
มูลค่าหมึก

คำตอบ:


12

เยลลี่ ,  14 12 11  9 ไบต์

-2 ไบต์ขอบคุณ ETHproductions (ใช้ dyad ขั้นต่ำ«)

I’«0Ṛ+\Ṛ+

ลิงก์ monadic ที่รับและส่งคืนรายการจำนวนเต็ม

ลองออนไลน์! หรือดูชุดทดสอบ

ฉันไม่คิดว่านี่เป็น Lazy ™มากพอ!

อย่างไร?

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 ไบต์

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

กรณีทดสอบ


7

เยลลี่ 12 ไบต์

I»1U
0ị;Ç_\U

ลองออนไลน์!

มันทำงานอย่างไร

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.

แนวคิดพื้นฐานในการเล่นคือ: ถ้าคุณย้อนกลับอาร์เรย์อินพุทและเอาท์พุทเอาต์พุตเป็นเพียงอินพุตที่มีแต่ละเดลต้าที่ 0 หรือมากกว่าแทนที่ด้วย -1 ตัวอย่างเช่น:

[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 ไบต์

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

ลองออนไลน์

คำอธิบาย:

{                  } /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 ไบต์

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

ลองออนไลน์!

aเก็บส่วนแรกของรายการในพารามิเตอร์ ในแต่ละขั้นตอนเพิ่มองค์ประกอบถัดไปxที่ส่วนท้ายของaและเพิ่มองค์ประกอบทั้งหมดของโดยขั้นต่ำของและ(y-x-1)0



3

C #, 76 ไบต์

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

สิ่งนี้จะแก้ไขรายการในสถานที่ มันจะผ่านรายการไปข้างหลังและเก็บเดลต้ารวมที่จะใช้กับแต่ละหมายเลข


2

JavaScript (ES6), 59 ไบต์

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

ว้าว. ฉันกำลังจะเขียนโซลูชัน JS แต่จากนั้นฉันเห็นสิ่งนี้ ฉันไม่คิดว่าจะใช้ตัวดำเนินการสเปรดแบบนั้นในพารามิเตอร์
andrewarchi

คุณสามารถออกไปf=สำหรับคำตอบ JS เพื่อประหยัดสองไบต์
andrewarchi

@andrewarchi ขอบคุณ แต่ฟังก์ชั่นนี้โดยเฉพาะต้องเรียกตัวเอง ( f(a)) ดังนั้นมันยังคงต้องใช้ชื่อ
ETHproductions

ฉันลืมว่ามันเป็นแบบเรียกซ้ำ
andrewarchi

2

Brain-Flakขนาด 153 ไบต์

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

ลองออนไลน์!

ซึ่งรวมถึง+1สำหรับ-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 ไบต์

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


1
การใช้งานที่ดีdiffฉันพยายามคิดว่าจะทำอย่างไรให้ได้ผล ... โดยวิธีการที่คุณสามารถกำจัดวงเล็บปีกการอบ ๆ ร่างกายของฟังก์ชั่นสำหรับ -2 ไบต์ แต่ยังดีกว่าคุณสามารถใช้s=scan()แทนฟังก์ชันได้ คำจำกัดความเพื่อบันทึกอีกสองสามไบต์ คงจะดีมากถ้าคุณมีลิงค์สำหรับทดลองใช้ออนไลน์เพื่อให้ผู้อื่นสามารถตรวจสอบได้ว่ารหัสนี้ใช้ได้กับทุกกรณีทดสอบ
Giuseppe

ไม่ต้องห่วง! เราทุกคนเริ่มต้นที่ไหนสักแห่ง :)
จูเซปเป้

1

JavaScript (ES6), 68 ไบต์

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

อินพุตและเอาต์พุตเป็นอาร์เรย์ของจำนวนเต็ม

ตัวอย่างการทดสอบ

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 ไบต์

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

คำอธิบาย:

นี่เป็นโซลูชันแบบเรียกซ้ำซึ่งโคลนอาร์เรย์ครั้งแรกจากนั้นจะลดค่าทั้งหมดจนกว่าองค์ประกอบจะมากกว่าหรือเท่ากับองค์ประกอบถัดไปในอาร์เรย์

ฟังก์ชั่นเรียกตัวเองตราบเท่าที่องค์ประกอบใด ๆ ที่ไม่เป็นระเบียบ เมื่อองค์ประกอบถูกจัดเรียงในที่สุดโคลนจะถูกส่งกลับ (เราไม่สามารถคืนอาเรย์เองได้เพราะsome()วิธีการจะทำให้องค์ประกอบทั้งหมดลดลงทำให้มันหมดไปด้วย -1)

กรณีทดสอบ:

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 ไบต์

:-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]).

อาจลองออนไลน์ได้ที่นี่: http://swish.swi-prolog.org/p/LazySort.pl

คุณถามl(L, [10,5,7,6,1]).ว่า "แก้ปัญหาสำหรับ L โดยที่ L เป็นรุ่นที่เรียงลำดับแบบขี้เกียจของรายการนี้"

ทั้งสองฟังก์ชั่นคือ:

  • lazysorted (A, B) - ระบุว่า A เป็นรุ่น lazysorted ของ B หากทั้งคู่เป็นรายการว่างหรือถ้า A สามารถรับได้โดยการสลับ B ให้เรียกฟังก์ชันผู้ช่วยเพื่อเดินรายการและทำการลบด้วยแอคคูเลเตอร์ ผลักแต่ละค่าต่ำกว่าค่าก่อนหน้าและย้อนกลับผลลัพธ์ของกลับไปทางที่ถูกต้อง
  • fผู้ช่วยตรงกับสองรายการค่าของหมายเลขก่อนหน้าในรายการและสะสมความแตกต่างกลิ้งและแก้ไขค่าใหม่ของตำแหน่งรายการปัจจุบันเป็นค่าเดิมลบค่าความแตกต่างสะสมลบค่าใหม่ที่จำเป็นในการบังคับนี้ ค่าต่ำกว่าหมายเลขก่อนหน้าในรายการและfต้องแก้สำหรับส่วนท้ายของรายการซ้ำด้วยการสะสมผลต่างที่เพิ่มขึ้นในขณะนี้

สกรีนช็อตของกรณีทดสอบบน Swish:

ภาพแสดงเคสทดสอบที่รันบน Swish


0

JavaScript (ES6), 61 ไบต์

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

ไม่ใช่ทางออกที่สั้นที่สุด reduceRightแต่ฉันไม่สามารถผ่านไปโอกาสที่จะใช้งาน


0

C # (. NET Core) , 89 88 86 79 ไบต์

  • บันทึกเพียง 1 ไบต์ด้วยวิธีการที่แตกต่างกันเล็กน้อย
  • บันทึกอีก 2 ไบต์ด้วยความเรียบง่ายของfors
  • บันทึกแล้ว 7 ไบต์ด้วยทักษะการเล่นกอล์ฟที่ยอดเยี่ยมของ VisualMelon
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;}

ลองออนไลน์!

อันดับแรกforวนซ้ำผ่านอาร์เรย์จากนั้นจะคำนวณการลดลงและสุดท้ายจะforลดองค์ประกอบที่สองลงหากจำเป็นจนถึงiตำแหน่งที่

ถูกต้องหรือไม่เพียงแค่ปรับเปลี่ยนอาร์เรย์เดิมแทนที่จะส่งคืนใหม่ (ยังคงคุ้นเคยกับกฎ)


ใช่การแก้ไขอาเรย์ดั้งเดิมนั้นดีมาก :)
DJMcMayhem

4
@DJMcMayhem ขอบคุณฉันรู้สึกขี้เกียจเกินไปที่จะสร้างใหม่ :)
Charlie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.