คำถามการเรียงลำดับคลาสสิกคำถามกอล์ฟ


11

นี่คือคำถามที่รหัสกอล์ฟ

อินพุต

รายการจำนวนเต็มที่ไม่เป็นลบในรูปแบบใดจะสะดวกที่สุด

เอาท์พุต

รายการเดียวกันเรียงตามลำดับในรูปแบบที่สะดวกที่สุด

การ จำกัด

  • รหัสของคุณจะต้องทำงานในเวลา O (n log n) ในกรณีที่เลวร้ายที่สุดซึ่งnเป็นจำนวนเต็มในอินพุต ซึ่งหมายความว่า quicksort แบบสุ่มหมดตัวอย่างเช่น อย่างไรก็ตามมีตัวเลือกอื่น ๆ ให้เลือกมากมาย
  • อย่าใช้ไลบรารี / ฟังก์ชั่น / การเรียงลำดับที่คล้ายกัน อย่าใช้อะไรที่ทำให้การเรียงลำดับส่วนใหญ่เหมาะกับคุณเช่นห้องสมุดกอง โดยพื้นฐานไม่ว่าคุณจะใช้อะไรก็ตามจงนำไปใช้ตั้งแต่เริ่มต้น

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

กรณีทดสอบ

In: [9, 8, 3, 2, 4, 6, 5, 1, 7, 0]
Out:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In: [72, 59, 95, 68, 84]
Out:[59, 68, 72, 84, 95]

In: [2, 2, 1, 9, 3, 7, 4, 1, 6, 7]
Out:[1, 1, 2, 2, 3, 4, 6, 7, 7, 9]

In: [2397725, 1925225, 3304534, 7806949, 4487711, 8337622, 2276714, 3088926, 4274324,  667269]
Out:[667269,1925225, 2276714, 2397725,3088926, 3304534, 4274324, 4487711, 7806949, 8337622]

คำตอบของคุณ

โปรดระบุอัลกอริทึมการเรียงลำดับที่คุณใช้งานและความยาวของโซลูชันในหัวข้อคำตอบของคุณ

ขั้นตอนวิธีการเรียงลำดับเวลา O (n log n)

มีอัลกอริธึมเวลา O (n log n) มากมาย ตารางนี้มีรายการบางส่วนของพวกเขา


ฟังก์ชั่นการตั้งค่าบางอย่างเช่นintersectเรียงลำดับอาร์เรย์โดยอัตโนมัติ ฉันเดาว่าคุณต้องการออกกฎเหล่านั้นด้วย วิธีการเกี่ยวกับunique(ลบรายการที่ซ้ำกันเรียงลำดับผล)?
Luis Mendo

@ DonMuesli ฉันทำ .. ฉันคิดว่าintersectมาภายใต้ "คล้ายกัน" ถ้ามันเรียงลำดับโดยอัตโนมัติ หากคุณลบรายการที่ซ้ำกันคุณจะให้ผลลัพธ์ที่ไม่ถูกต้อง

เกี่ยวกับการป้อนข้อมูลผิดปล่อยให้ฉัน :-) จากนั้นสามารถ "ลบรายการที่ซ้ำกันและเรียงลำดับ" ถูกใช้ไหม
Luis Mendo

3
Nitpick: 0 ไม่ใช่จำนวนเต็มบวก (ภายใต้อินพุต )
บีกเกอร์

1
ฉันชอบวิธีที่เร็วที่สุดเมื่อคำถามมีส่วนเกี่ยวข้องกับการแสดงทุกคนแห่กันออกไปจากภาษากอล์ฟแม้ว่านี่จะยังคงเป็นรหัสกอล์ฟและทางออกที่สั้นที่สุดก็จะชนะ
Cyoce

คำตอบ:


8

Haskell, 87 80 89

s%[]=s
(x:a)%q|x<=q!!0=x:a%q
p%q=q%p
j(x:y:s)=x%y:j s
j a=a
r[x]=x
r s=r$j s
s=r.map(:[])

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

(%)เป็นฟังก์ชั่นการ
jผสานผสานคู่ในรายการของการ
rรวมรายการที่สมบูรณ์ของรายการ
sคือฟังก์ชั่นการเรียงลำดับ

การใช้งาน: s [3,5,2,6,7]ทำงานเป็นล่ามและป้อน

แก้ไข: วิธีที่ฉันรวมสิ่งต่าง ๆ ก่อนหน้านี้ไม่ใช่ลำดับที่ถูกต้องดังนั้นในการแก้ไขฉันต้องการอักขระเพิ่มอีก 9 ตัว


1
@Lembik ถ้าคุณต้องการทดสอบโปรแกรมและคุณไม่ต้องการติดตั้ง Haskell คุณสามารถใช้ ideone และเพิ่มบรรทัดที่ต้องการmain = print (s [5,3,6,8])ซึ่งจะตั้งค่าหลักในการพิมพ์ผลลัพธ์ของการเรียงลำดับ
ภูมิใจ haskeller

ฉันคิดว่าคุณไม่ต้องการ[]%s=sเพราะถ้าองค์ประกอบแรกคือ[]การ(x:a)แข่งขันล้มเหลวและกรณีสุดท้ายพลิกองค์ประกอบเพื่อที่จะs%[]ประสบความสำเร็จ
nimi

คุณเป็นผู้ชนะ! คำตอบเดียวที่ใช้ไบต์น้อยลงไม่ได้ทำงานใน O (n log n)

@ Lembik ใช่ฉันลืมคำตอบของ Jelly ไม่ได้ปฏิบัติตาม
ภูมิใจ haskeller

1
ดูเหมือนว่าตอนนี้ :)

5

JavaScript (ES6), 195 193 191 189 188 186 183 182 179 174 172 ไบต์

นี่เป็นการใช้งานฮีปพอร์ต ฉันคาดหวังว่าจะมีคนมารวมกับการรวมกลุ่มที่สั้นกว่า แต่ฉันชอบอันนี้: P

Update: R ผสานการตี ทับทิมขึ้นถัดไป: D

S=l=>{e=l.length
W=(a,b)=>[l[a],l[b]]=[l[b],l[a]]
D=s=>{for(;(c=s*2+1)<e;s=r<s?s:e)s=l[r=s]<l[c]?c:s,W(r,s=++c<e&&l[s]<l[c]?c:s)}
for(s=e>>1;s;)D(--s)
for(;--e;D(0))W(0,e)}

ทดสอบ (Firefox)


ฉันชอบที่จะเขียนคำตอบ heapsort แต่มันก็ใช้งานไม่ได้กับ Haskell ความพยายามครั้งต่อไปของฉันคือ JS แต่คุณได้ทำไปแล้ว บางทีฉันอาจจะยังคงทำอย่างนั้น Idk
ภูมิใจ haskeller

@proudhaskeller อาใช่ .. ฉันเพียงแค่เงยหน้าขึ้นมองstackoverflow.com/a/2186785/2179021

3

Python3, 132 ไบต์

def S(l):
 if len(l)<2:return l
 a,b,o=S(l[::2]),S(l[1::2]),[]
 while a and b:o.append([a,b][a[-1]<b[-1]].pop())
 return a+b+o[::-1]

การรวมง่าย ๆ มีการใช้ไบต์จำนวนมากเพื่อให้แน่ใจว่าสิ่งนี้จะทำงานจริงใน O (n log n) หากเพียง แต่อัลกอริทึมแต่ไม่จำเป็นต้องใช้งาน O (n log n) สิ่งนี้สามารถทำให้สั้นลงได้:

Python3, 99 ไบต์

def m(a,b):
 while a+b:yield[a,b][a<b].pop(0)
S=lambda l:l[1:]and list(m(S(l[::2]),S(l[1::2])))or l

นี่ไม่ใช่ O (n log n) เพราะ.pop(0)เป็น O (n) ทำให้ฟังก์ชันการรวม O (n ^ 2) แต่นี่เป็นสิ่งที่ถูกประดิษฐ์ขึ้นมาพอ ๆ กับ.pop(0)O (1)


ขอบคุณสำหรับสิ่งนี้. ฉันหมายถึงอัลกอริทึมและการติดตั้งควรเป็น O (n log n)

เพื่อให้ชัดเจนนี่หมายความว่ารุ่น 132 นั้นใช้ได้ แต่รุ่น 99 ไบต์ไม่สอดคล้อง

2

Julia, 166 ไบต์

m(a,b,j=1,k=1,L=endof)=[(j<=L(a)&&k<=L(b)&&a[j]<b[k])||k>L(b)?a[(j+=1)-1]:b[(k+=1)-1]for i=1:L([a;b])]
M(x,n=endof(x))=n>1?m(M(x[1:(q=ceil(Int,n÷2))]),M(x[q+1:n])):x

ฟังก์ชั่นหลักที่เรียกว่าและเรียกฟังก์ชั่นผู้ช่วยM mมันใช้การเรียงลำดับผสานซึ่งมีO ( n log n ) เป็นความซับซ้อนของกรณีที่เลวร้ายที่สุด

ตัวอย่างการใช้:

x = [9, 8, 3, 2, 4, 6, 5, 1, 7, 0]
println(M(x))              # prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
println(M(x) == sort(x))   # prints true

Ungolfed:

function m(a, b, i=1, k=1, L=endof)
    return [(j <= L(a) && k <= L(b) && a[j] < b[k]) || k > L(b) ?
            a[(j+=1)-1] : b[(k+=1)-1] for i = 1:L([a; b])]
end

function M(x, n=endof(x))
    q = ceil(Int, n÷2)
    return n > 1 ? m(M(x[1:q]), M([q+1:n])) : x
end

ดีใจที่ได้เห็น Julia ที่นี่ ตอนนี้เราจำเป็นต้องใช้สิ่งที่เป็นสนิมและเป็นสนิมด้วยเช่นกัน :)

1
@ Lembik ฉันคิดว่า Sp3000 และ Doorknob เป็นผู้เชี่ยวชาญ Nim และ Rust ของเราตามลำดับ หวังว่าพวกเขาจะเข้าร่วมสนุกเช่นกัน ;)
Alex A.

2

R, 181 bytes, Mergesort

L=length;s=function(S)if(L(S)<2){S}else{h=1:(L(S)/2);A=s(S[h]);B=s(S[-h]);Z=c();if(A[L(A)]>B[1])while(L(A)&L(B))if(A[1]<B[1]){Z=c(Z,A[1]);A=A[-1]}else{Z=c(Z,B[1]);B=B[-1]};c(Z,A,B)}

เยื้องกับบรรทัดใหม่:

L=length
s=function(S)
    if(L(S)<2){
        S
    }else{
        h=1:(L(S)/2)
        A=s(S[h])
        B=s(S[-h])
        Z=c()
        if(A[L(A)]>B[1])
#Merge helper function incorporated from here ...
            while(L(A)&L(B))
                if(A[1]<B[1]){
                    Z=c(Z,A[1])
                    A=A[-1]
                }else{
                    Z=c(Z,B[1])
                    B=B[-1]
                }
#...to here. Following line both finishes merge function and handles 'else' case:
        c(Z,A,B)
    }

กรณีทดสอบ:

> L=length;s=function(S)if(L(S)<2){S}else{h=1:(L(S)/2);A=s(S[h]);B=s(S[-h]);Z=c();if(A[L(A)]>B[1])while(L(A)&L(B))if(A[1]<B[1]){Z=c(Z,A[1]);A=A[-1]}else{Z=c(Z,B[1]);B=B[-1]};c(Z,A,B)}
> s(c(2397725, 1925225, 3304534, 7806949, 4487711, 8337622, 2276714, 3088926, 4274324,  667269))
 [1]  667269 1925225 2276714 2397725 3088926 3304534 4274324 4487711 7806949 8337622
> s(c(2, 2, 1, 9, 3, 7, 4, 1, 6, 7))
 [1] 1 1 2 2 3 4 6 7 7 9
> s(c(72, 59, 95, 68, 84))
 [1] 59 68 72 84 95
> s(c(9, 8, 3, 2, 4, 6, 5, 1, 7, 0))
 [1] 0 1 2 3 4 5 6 7 8 9

2

ฟังก์ชั่น Scala, 243 ไบต์ (แอพแบบสแตนด์อะโลน 315 ไบต์), รวมกัน

คำตอบนี้มีวัตถุประสงค์เพื่อใช้เป็นฟังก์ชัน แต่สามารถขยายให้เป็นแอปพลิเคชันแบบสแตนด์อะโลนได้

ฟังก์ชั่นเท่านั้น (243 ไบต์):

object G{
type S=Stream[Int]
def m(f:(S,S)):S=f match{
case(x#::a,b@(y#::_))if x<=y=>x#::m(a,b)
case(a,y#::b)=>y#::m(a,b)
case(a,Empty)=>a
case(_,b)=>b}
def s(a:S):S=if(a.length>1)((q:S,w:S)=>m(s(q),s(w))).tupled(a.splitAt(a.length/2))else a
}

แอปพลิเคชันแบบสแตนด์อโลน (315 ไบต์):

object G extends App{
type S=Stream[Int]
def m(f:(S,S)):S=f match{
case(x#::a,b@(y#::_))if x<=y=>x#::m(a,b)
case(a,y#::b)=>y#::m(a,b)
case(a,Empty)=>a
case(_,b)=>b}
def s(a:S):S=if(a.length>1)((q:S,w:S)=>m(s(q),s(w))).tupled(a.splitAt(a.length/2))else a
println(s(args(0).split(",").map(_.toInt).toStream).toList)
}

การใช้งาน:

ฟังก์ชั่น: G.s(List(**[Paste your array here]**).toStream).toList

การประยุกต์ใช้: sbt "run **[Paste your array here]**"

อินพุตตัวอย่าง:

scala> G.s(List(10,2,120,1,8,3).toStream).toList

(OR)

$ sbt "run 5423,123,24,563,65,2,3,764"

เอาท์พุท:

res1: รายการ [Int] = รายการ (1, 2, 3, 8, 10, 120)

หรือ

รายการ (2, 3, 24, 65, 123, 563, 764, 5423)

ข้อ จำกัด และข้อควรพิจารณา:

  • ต้องการ scalaz (ไลบรารี่ทั่วไปที่ไม่ได้ใช้สำหรับการเรียงลำดับที่นี่)
  • ทำงานได้ 100% (ไม่มีการเปลี่ยนแปลงใด ๆ !)

ที่มา:


2

เยลลี่, 29 ไบต์, เรียงลำดับการผสาน

เช่นเดียวกับคำตอบของ orlp หลามใช้นี้list.pop(0)ภายใต้ประทุนซึ่งเป็นแต่การดำเนินการอย่างเป็นทางการO(n)O(n log n)

ṛð>ṛḢð¡Ḣ;ñ
ç;ȧ?
s2Z߀ç/µL>1µ¡

ลองที่นี่

คำอธิบาย

               Define f(x, y):    (merge helper)
                 Implicitly store x in α.
ṛ    ð¡          Replace it with y this many times:
 ð>ṛḢ              (x > y)[0].
       Ḣ         Pop the first element off that list (either x or y).
        ;ñ       Append it to g(x, y).

               Define g(x, y):    (merge)
  ȧ?             If x and y are non-empty:
ç                  Return f(x, y)
                 Else:
 ;                 Return concat(x, y).

               Define main(z):    (merge sort)
       µL>1µ¡    Repeat (len(z) > 1) times:
s2                 Split z in chunks of length two.   [[9, 7], [1, 3], [2, 8]]
  Z                Transpose the resulting array.     [[9, 1, 2], [7, 3, 8]]
   ߀              Apply main() recursively to each.  [[1, 2, 9], [3, 7, 8]]
     ç/            Apply g on these two elements.     [1, 2, 3, 7, 8, 9]

คุณช่วยเพิ่มคำอธิบายได้ไหม

มีจำนวนมากที่จะอธิบาย :) ให้ฉันดูเป็นว่าฉันสามารถกอล์ฟลงบรรทัดสุดท้ายบิตขนาดเล็กมากขึ้น
ลินน์

เมื่อคุณพูดว่าการใช้งานคือ O (n log n) แต่ใช้ list.pop (0) ภายใต้ประทุนซึ่งเป็น O (n) ฉันสับสน คุณหมายถึงอะไร

ฉันหมายถึงสิ่งที่ orlp เขียนไว้ในคำตอบของเขา: นี่ไม่ใช่ O (n log n) เพราะ.pop(0)เป็น O (n) ทำให้การรวมฟังก์ชัน O (n ^ 2) แต่นี่เป็นสิ่งที่ถูกประดิษฐ์ขึ้นมาพอ ๆ กับ.pop(0)O (1)
Lynn

วุ้นจะดำเนินการในหลามและจะดำเนินการเป็น .pop(0)
Lynn

1

Ruby, 167 ไบต์

อัลกอริทึมการเรียงลำดับผสาน Golfed ซึ่งมีตัวพิมพ์เล็กที่สุด O (n บันทึก n)

f=->x{m=->a,b{i,j,l,y,z=0,0,[],a.size,b.size
while i<y&&j<z
c=a[i]<b[j]
l<<(c ?a[i]:b[j])
c ?i+=1:j+=1
end
l+=a[i,y]+b[j,z]}
l=x.size
l>1?m[f[x[0,l/2]],f[x[l/2,l]]]:x}

ทดสอบที่นี่!

ในการทดสอบคัดลอกและวางรหัสลงในหน้าต่างและเพิ่มputs f[x]ที่ด้านล่างโดยที่ x คืออาร์เรย์ที่มีอินพุต (ให้แน่ใจว่าคุณเลือก Ruby เป็นภาษาของหลักสูตร) ​​ตัวอย่างเช่นputs f[[2, 2, 1, 9, 3, 7, 4, 1, 6, 7]]


ขอบคุณสำหรับสิ่งนี้! คุณช่วยแสดงให้เห็นว่ามันใช้งานได้เช่นกัน?

1
ฉันเพิ่มลิงก์เพื่อให้คุณสามารถทดสอบได้
มูลค่าหมึก

1

Ruby, 297 ไบต์

เรียงลำดับการผสาน เสร็จสิ้นโปรแกรมแทนฟังก์ชั่น ต้องมีอาร์กิวเมนต์สองตัวที่รันไทม์: ไฟล์อินพุตและไฟล์เอาต์พุตแต่ละไฟล์มีหนึ่งองค์ประกอบต่อบรรทัด

if $0==__FILE__;v=open(ARGV[0]).readlines.map{|e|e.to_i}.map{|e|[e]};v=v.each_slice(2).map{|e|a,b,r=e[0],e[1],[];while true;if(!a)||a.empty?;r+=b;break;end;if(!b)||b.empty?;r+=a;break;end;r<<(a[0]<b[0]?a:b).shift;end;r}while v.size>1;open(ARGV[1],"w"){|f|f.puts(v[0].join("\n"))if !v.empty?};end

ถ้ามันสั้นลงรหัสของคุณคุณควรพิจารณาปรับรหัสให้เป็นฟังก์ชั่นที่ได้รับอาร์เรย์เป็นอินพุตและส่งกลับลำดับที่เรียงลำดับ ดูเหมือนว่าคุณจะได้รับการกำจัดจำนวนไบต์
ภูมิใจ haskeller

หากคุณจะเก็บมันไว้เป็นโปรแกรมเต็มรูปแบบแทนที่จะใช้ฟังก์ชั่นฉันขอแนะนำให้ใช้ STDIN และ STDOUT เป็นอินพุต / เอาต์พุตตามลำดับหรือไม่ $stdin.readlinesแล้วเป็นไบต์น้อยกว่าopen(ARGV[0]).readlinesเช่นเดียวกับputsกว่าopen(ARGV[1],"w"){|f|f.puts
ราคาหมึก

2
และสิ่งที่ชอบif $0==__FILE__ไม่จำเป็นจริงๆในการตีกอล์ฟ นอกจากนี้คุณยังอาจรวมตัวแทนที่;ด้วยขึ้นบรรทัดใหม่ - มันเป็นจำนวนไบต์เดียวกันและ (อาจ) ลบการเลื่อนแนวนอนของรหัส นอกจากนี้ผมจะแนะนำการตรวจสอบเคล็ดลับสำหรับการเล่นกอล์ฟในรูบี
daniero
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.