รวมสองรายการที่เรียงลำดับ


14

ผสานเรียง

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

- อัลกอริทึมของคุณจะต้องใช้เวลาเชิงเส้นแบบเชิงเส้นเท่ากับขนาดของอินพุต โปรดหยุดการแก้ปัญหา O (n ^ 2)

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

ตัวอย่าง:

merge([1],[0,2,3,4])
[0,1,2,3,4]

merge([1,5,10,17,19],[2,5,9,11,13,20])
[1, 2, 5, 5, 9, 10, 11, 13, 17, 19, 20]

นี่คือดังนั้นรหัสที่สั้นที่สุดอาจชนะ!


เราต้องจัดการองค์ประกอบที่ซ้ำกันภายในรายการหรือเฉพาะระหว่างสองรายการ
Keith Randall

สมมติว่าทั้งสอง แนวคิดคือคุณควรใช้สิ่งนี้เพื่อรวมการเรียงลำดับ
isaacg

มันเป็นโคเชอร์ที่จะปิดบังอาร์เรย์อินพุตหรือไม่?
skibrianski

3
ผมไม่แน่ใจว่าวิธีการตีความขั้นตอนวิธีการต้องใช้ในปริมาณเชิงเส้น asymptotically ของเวลา อัลกอริทึมไม่ต้องใช้เวลาการใช้งานทำ เวลาดำเนินการของคำตอบ Golfscript ของฉันคือ O (น่ากลัว) กับล่าม Ruby แต่Online Golfscript Testerทำงานได้ดีขึ้นมากและในความเป็นจริงอาจเป็นเชิงเส้น จุดของฉันคือ: b=a;b=b.lengthอาจทำซ้ำอาร์เรย์ทั้งหมดa(และส่งผลให้เวลา O (n ^ 2) ถ้าดำเนินการสำหรับทุกองค์ประกอบ) หรือทำซ้ำเพียงอ้างอิงถึงอาร์เรย์ (O (n) เวลา) อันไหนมีค่า?
เดนนิส

1
ฉันเดาว่าในกรณีเช่นนี้ลองทำอย่างดีที่สุด แต่ถ้าคุณไม่สามารถบอกได้อย่างตรงไปตรงมาคุณสามารถสมมติว่าสิ่งต่าง ๆ ทำงานได้ดีเหมือนทางเลือกที่สองที่คุณพูดถึง คุณสามารถสมมติว่าล่ามทำงานได้ดีหากภาษาของคุณไม่มีล่ามมาตรฐาน
isaacg

คำตอบ:


8

Rebmu ( 35 32 ตัวอักษร)

u[iG^aNXa[rvA]apGtkFaM?fA]apGscA

ทดสอบ

>> rebmu/args [u[iG^aNXa[rvA]apGtkFaM?fA]apGscA] [[1 5 10 17 19] [2 5 9 11 13 20]] 
== [1 2 5 5 9 10 11 13 17 19 20]

>> rebmu/args [u[iG^aNXa[rvA]apGtkFaM?fA]apGscA] [[2 5 9 11 13 20] [1 5 10 17 19]] 
== [1 2 5 5 9 10 11 13 17 19 20]

เกี่ยวกับ

Rebmuเป็นภาษาของ Rebol ที่อนุญาตให้ 'mushing' ของรหัสปกติสำหรับสถานการณ์ที่ต้องการความกระชับ Unmushed โค้ดใช้งานได้ดีเช่น:

u [                     ; until
    i g^ a nx a [       ; if greater? args next args
       rv a             ; reverse args
    ]                   ; (we want the block containing the next value first)

    ap g tk f a         ; append output take first args
    m? f a              ; empty? first args
]                       ; (first block is now empty)

ap g sc a               ; append output second args
                        ; (add the remainder of the second)

ฉันเชื่อว่าสิ่งนี้ตรงตามข้อกำหนดO (n)เนื่องจากจนกว่าบล็อกจะวนซ้ำหลาย ๆ ครั้งตามความยาวของอินพุต (และreverseเพียงสลับลำดับของคอนเทนเนอร์ของบล็อกอินพุตเท่านั้นไม่ใช่บล็อกตัวเอง) การใช้takeอาจเป็นอิสระ แต่ก็ยังมีประสิทธิภาพเล็กน้อย

Rebol ( 83 75 ตัวอักษร)

เพียงแค่แตกต่างกันเล็กน้อยกระจ้อยร่อยใน REBOL เส้นทางที่มีการแสดงออกที่สั้นกว่าหรือfirstsecondaคือบล็อกอินพุตที่มีสองบล็อก:

until[if a/2/1 < a/1/1[reverse a]append o:[]take a/1 tail? a/1]append o a/2

5

โซลูชั่นของ OP:

Haskell 49 44 40

k@(p:r)%l@(q:s)|p>=q=q:k%s|0<1=l%k
a%_=a

Python 131 105 101 99 93

ด้วยความขอบคุณ @Evpok:

f=lambda u,v:v and(v[-1]<u[-1]and f(v,u)or[b.append(a)for a,b in[(v.pop(),f(u,v))]]and b)or u

1
คุณสามารถเขียนa%b=a++bหลังจากการจับคู่รูปแบบหลักเพื่อจัดการรายการที่ว่างซึ่งจะกำจัดอักขระบางตัว
swish

โซลูชัน Haskell จึงล้มเหลวหากรายการแรกหมดเนื้อหาก่อน
John Dvorak

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

4

Python (79)

from itertools import*
def m(*a):
 while any(a):yield min(compress(a,a)).pop(0)

Python (95 ถ้าเราไม่ได้รับอนุญาตให้ส่งคืนเครื่องกำเนิดไฟฟ้า)

from itertools import*
def m(*a):
 r=[]
 while any(a):r+=[min(compress(a,a)).pop(0)]
 return r

Itertools เป็นทางออกสำหรับปัญหาทางโลกทั้งหมด

โบนัส: ทั้งสองงานนี้มีจำนวนรายการตามอำเภอใจและไม่ต้องกังวลเกี่ยวกับรายการว่างเปล่า (เช่นพวกเขาจะทำรายการว่างเปล่า 2 รายการอย่างมีความสุขและส่งคืนรายการเปล่าหรือรับ 1 รายการที่ว่างและไม่ว่าง 1 รายการ และพวกเขาจะส่งคืนค่าที่ไม่ว่างเปล่าคุณลักษณะเพิ่มเติมที่เพิ่มเข้ามาของ 2 รายการที่ไม่ได้ผล: พวกเขาจะเรียกใช้โดยไม่มีข้อโต้แย้งและกลับรายการว่างเปล่า)

Ungolfed:

from itertools import *  # Import all items from itertools
def m(*a):               # Define the function m, that takes any number of arguments, 
                         #  and stores those arguments in list a
    r=[]                 # Create an empty list r                         
    while any(a):        # While any element in a returns True as value:
        b=compress(a,a)  # Remove any element from a that isn't True (empty lists)
                         #  The example in the official documentation is this one:
                         #  compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
        c=min(b)         # Sort the lists by first value, and take the first one of these.
        d=c.pop(0)       # Take the first element from c
        r.append(d)      # Append this first element to r
    return r             # Gives back r

ในการแก้ปัญหาของคุณโดยกำเนิดใช้r+=[...]แทนr.append(...)(ประหยัด 4 ตัวอักษรทุกครั้ง)
HLT

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

หากคุณแบ่งออกเป็นโพสต์ที่แตกต่างกันฉันจะลงคะแนนหลามหนึ่ง
undergroundmonorail

4
@undergroundmonorail คุณลงคะแนนคำตอบ GolfScript ทั้งหมดหรือไม่
Evpok

1
@ Evpok ตอนนี้คุณพูดถึงมันแล้วอาจจะโยนมันลงบนเมตาและดูสิ่งที่พวกเขาพูดที่นั่น
Aprıʇǝɥʇuʎs

3

C - 75

สิ่งนี้ทำงานในNULLอาร์เรย์ที่ถูกยกเลิกint *ถึงแม้ว่ามันจะทำงานได้ดีเท่ากันสำหรับตัวชี้ไปยังประเภทอื่นโดยแทนที่ฟังก์ชันการเปรียบเทียบที่เหมาะสมสำหรับ**b < **a(เช่นstrcmp(*b, *a) < 0)

void m(int**a,int**b,int**c){while(*a||*b)*c++=!*a||*b&&**b<**a?*b++:*a++;}

Ungolfed:

void merge(int **a, int **b, int **c)
{
    while(*a || *b)
        *c++ = !*a || *b && **b < **a
            ? *b++
            : *a++;
}

3

Golfscript, 29 27 30 29 26 ไบต์

~{.0=@.0=@<{}{\}if(@@.}do;~]p

หรือ

~{.0=@.0=@>{\}*(@@.}do;~]p

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

คำสั่ง

golfscript merge.gs <<< '[2 3] [1 4]'

จะได้รับการประมวลผลดังนี้:

~            # Interpret the input string.
             #
             # STACK: [2 3] [1 4]
{            #
    .@=0.@=0 # Duplicate the two topmost arrays of the stack and extract their first 
             # elements. This reverses the original order of the first copy.
             #
             # STACK: [1 4] [2 3] 2 1
             #
    >        # Check if the respective first elements of the arrays are ordered.
             #
             # STACK: [1 4] [2 3] 1
             #
    {\}*     # If they are not, swap the arrays. This brings the array with the smallest
             # element to the top of the stack.
             #
             # STACK: [2 3] [1 4]
             #
    (@@      # Shift the first element of the array on top of the stack and rotate it
             # behind the arrays.
             #
             # STACK: 1 [2 3] [4]
             #
    .        # Duplicate the topmost array.
             #
             # STACK: 1 [2 3] [4] [4]
             #
}do          # Repeat this process if the array is non-empty.
             #
             # STACK: 1 [2 3] [4] -> 1 2 [4] [3] -> 1 2 3 [4] []
             #
;~           # Delete the empty array from the stack and dump the non-empty array.
             #
             # STACK: 1 2 3 4
             #
]p           # Combine all elements on the stack into a single array, the to a string and
             # print.

ผลลัพธ์คือ:

[1 2 3 4]

การทำซ้ำอาร์เรย์ในสแต็กทำให้ O (n ^ 2) หรือไม่
swish

@swish: ฉันไม่ใช่นักวิทยาศาสตร์คอมพิวเตอร์ แต่ฉันว่ามันขึ้นอยู่กับการใช้งาน หากล่ามทำซ้ำอาร์เรย์ทั้งหมดจริง ๆ ฉันคิดว่าเป็นเช่นนั้น
Dennis

รุ่นก่อนหน้าคือ O (n ^ 2) สำหรับอาร์เรย์ที่คล้ายกันมาก (เช่น[1 1 1 ... 2]และ[1 1 1 ... 3]) เนื่องจากการเปรียบเทียบอาร์เรย์ (แทนที่จะเป็นองค์ประกอบแรก) จะช้ามากในกรณีนี้
เดนนิส

การทำงานของอาเรย์เดียวที่เกิดขึ้นในเวอร์ชั่นใหม่คือการทำซ้ำการสลับและการหมุนบนสแต็ก เนื่องจากอาร์เรย์ที่ทำซ้ำจะถูกใช้เพื่อแยกองค์ประกอบเดียวและทดสอบอาร์เรย์สำหรับความไม่ว่างเปล่า (การดำเนินการทำลายล้างทั้งใน Golfscript) รหัสข้างต้นสามารถทำงานในเวลา O (n) (โดยการทำซ้ำการแลกเปลี่ยนและหมุนการอ้างอิงไปยัง อาร์เรย์) ประสิทธิภาพที่แท้จริงขึ้นอยู่กับล่าม
Dennis

2

เจ - 42 33

แก้ไขเวอร์ชันจากที่นี่ + ความคิดเห็นของ @algorithmshark

k=:(m}.),~0{]
m=:k~`k@.(>&{.) ::,

kเพิ่มหัวของอาร์เรย์ที่ถูกต้องให้กับส่วนท้ายที่ผสานของทั้งสองอาร์เรย์ k~เหมือนกัน แต่มีการพลิกอาร์เรย์ (>&{.)กำลังเปรียบเทียบหัว ,รหัสจะโยนความผิดพลาดอย่างใดอย่างหนึ่งของอาร์เรย์ที่ว่างเปล่าในกรณีที่เรากลับมาเพียงแค่เรียงต่อกันของพวกเขา


ฉันคิดว่าเนื่องจาก/:~ a,bเป็นคำตอบที่ต้องห้าม (พร้อมด้วย[:/:~,) คุณกำลังถ่ายทำสำหรับคำตอบที่สั้นที่สุดที่ไม่รวม/:ใช่มั้ย
Dane

ฉันจะชี้ให้เห็นว่าคำถามระบุว่า "ไม่ต้องกังวลกับรายการที่ว่างเปล่า"
Dane

@Dane การทดสอบความว่างเปล่าที่จำเป็นสำหรับการเรียกซ้ำเพื่อหยุด
swish

m=:k~`k@.(>&{.)`,@.(0=*&#)ประหยัด 2 ถ่าน
algorithmshark

ในความเป็นจริงคุณจะได้รับสิ่งที่ลงทั้ง 33 ถ่าน: และk=:(m}.),~0{] m=:k~`k@.(>&{.) ::,เราใช้ที่จะโยนความผิดพลาดเมื่อรายการว่างเปล่าแล้วจับที่ผิดพลาดและออกด้วย0{ ,
algorithmshark

2

JavaScript (ES6), 69 79 ไบต์

f=(a,b,c=[])=>(x=a[0]<b[0]?a:b).length?f(a,b,c.concat(x.shift())):c.concat(a,b)

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

f = (a, b, c = []) =>          // `f' is a function that takes arguments `a', `b' and `c' -
                               // `c' defaults to `[]' - which returns the following
                               // expression:
                               //
 (x = a[0] < b[0] ? a : b)     // Store the array among `a' and `b' with the smaller first 
                               // element in `x'.
                               //
 .length ?                     // If it's non-empty,
                               //
  f(a, b, c.concat(x.shift())) // append the first element of array `x' to array `c' and run
                               // `f' again;
                               //
  : c.concat(a,b)              // otherwise, append the arrays `a' and `b' to `c'.
                               //
)

การเปรียบเทียบอาร์เรย์กับ<โอเปอเรเตอร์นั้นไม่ถูกต้องเนื่องจากทำการเปรียบเทียบสตริง:f([123, 456, 789], [1, 2, 3, 4, 5]) => [1, 123, 2, 3, 4, 456, 5, 789]
ขีดล่าง

@nderscore: ใช่ มันจะไม่ทำงานต่อไปเนื่องจากการเปรียบเทียบทั้งอาร์เรย์อาจไม่ใช่ O (n) ดูเหมือนว่าจะเป็นจริงสำหรับการทดสอบที่ไม่ใช่ความว่างเปล่าซึ่งจะต้องแปลงทั้งอาร์เรย์เป็นสตริง
Dennis

ใช่ฉันไม่แน่ใจว่าสิ่งที่ใหญ่สำหรับการแปลงอาเรย์ชนิดสตริงคืออะไร
ขีดล่าง

1
การต่ออาร์เรย์ด้วย[]แล้วแปลงเป็นสตริงต้องใช้เวลา O (n) การทำเช่นนี้หนึ่งครั้งสำหรับองค์ประกอบทั้งหมดของอาร์เรย์ต้องใช้เวลา O (n ^ 2)
เดนนิส

มีเหตุผล. เข้าใจแล้ว
nderscore

2

Python (63) (69) (71)

def m(a,b):
 if a[0]>b[0]:a,b=b,a
 return[a.pop(0)]+(m(a,b)if a else b)

ฉันเขียนสิ่งนี้ก่อนที่จะเห็นความคิดเห็นของ OP เกี่ยวกับ runtimes ของคำตอบอื่น ๆ ดังนั้นนี่เป็นอีกวิธีการหนึ่งที่ใช้ O (n) ในอัลกอริทึม แต่ไม่ใช่การนำไปใช้


อัลกอริทึมใดที่มีการแยกข้อมูลจากด้านหน้าของอาร์เรย์เป็น O (1) อัลกอริทึมใดที่มีการเปรียบเทียบรายการที่ใช้ O (1) นอกจากนี้คุณสามารถเล่นกอล์ฟต่อไปได้โดยเปลี่ยน ... ถ้า ... อื่น ... เป็น ... และ ... หรือ ...
isaacg

@isaacg Shoot ฉันลืมเกี่ยวกับการทำซ้ำอาจทำให้การเปรียบเทียบรายการ O (n) ดังนั้นฉันจึงได้ทำการปรับปรุงให้เหมาะสมสำหรับตัวละครอีก 6 ตัว คุณสามารถแยกและต่อท้ายด้านหน้าใน O (1) ในรายการที่เชื่อมโยง ฉันไม่เห็นว่าคุณสามารถสร้าง ... และ ... หรือ ... เล่นได้ดีกับการคืนค่า
xnor

ตกลงฉันเห็นตอนนี้วิธีการทำ ... และ ... หรือ ... แต่มันไม่ได้บันทึกตัวอักษรเนื่องจากความต้องการของ parens return[a.pop(0)]+(a and m(a,b)or b)
xnor

@isaacg: การแยกด้านหน้าของอาร์เรย์ใน O (1) เพียงเพิ่มตัวชี้อาร์เรย์เพื่อให้ชี้ไปที่องค์ประกอบที่สองและปล่อยหน่วยความจำที่ใช้โดยองค์ประกอบแรก
Wrzlprmft

@Wrzlprmft ฉันไม่สามารถรับค่าเคล็ดลับของอาร์เรย์ได้เนื่องจากองค์ประกอบทั้งสองของอาร์เรย์ได้รับการประเมินโดยไม่คำนึงถึงค่าบูลีนซึ่งจะโยนข้อผิดพลาดเมื่อรายการว่างเปล่า มีวิธีสั้น ๆ ในการสร้าง "lazy แถว" หรือไม่?
xnor

2

Haskell, 35 ไบต์

a#b@(c:d)|a<[c]=b#a|0<1=c:a#d
a#_=a

Haskell 30 ไบต์ (ไม่แข่งขัน)

รุ่นที่ไม่ใช่การแข่งขันนี้รับประกันรันไทม์เชิงเส้นเท่านั้นหากaและbมีองค์ประกอบที่แยกออกจากกัน; มิฉะนั้นจะยังคงทำงานอย่างถูกต้อง แต่อาจใช้เวลากำลังสอง

a#b|a<b=b#a|c:d<-b=c:a#d
a#_=a

2

PHP 91 98 91 ไบต์

แก้ไข # 1: ช่องว่าง$bต้องใช้เงื่อนไขเพิ่มเติมในเครื่องหมายปีกกา (+7)
แก้ไข # 2: golfings เล็กน้อย
แก้ไข # 3: เพิ่มรุ่นที่สอง

ตรงไปตรงมาสวย ส่วนที่อร่อยที่สุดคือ ternary ภายในarray_shift
(ซึ่งล้มเหลวถ้าคุณลองโดยไม่ต้องใช้ curlys)

function m($a,$b){for($c=[];$a|$b;)$c[]=array_shift(${$a&(!$b|$a[0]<$b[0])?a:b});return$c;}

หรือ

function m($a,$b){for($c=[];$a|$b;)$c[]=array_shift(${$a?!$b|$a[0]<$b[0]?a:b:b});return$c;}

ungolfed

function m($a,$b)
{
    $c=[];
    while($a||$b)
    {
        $c[] = array_shift(${
            $a&&(!$b||$a[0]<$b[0])
                ?a
                :b
        });
#       echo '<br>', outA($a), ' / ', outA($b) , ' -> ', outA($c);
    }
    return $c;
}

ทดสอบ

$cases = array (
    [1],[0,2,3,4], [0,1,2,3,4],
    [1,5,10,17,19],[2,5,9,11,13,20], [1, 2, 5, 5, 9, 10, 11, 13, 17, 19, 20],
    [1,2,3],[], [1,2,3],
    [],[4,5,6], [4,5,6],
);
function outA($a) { return '['. implode(',',$a). ']'; }
echo '<table border=1><tr><th>A</th><th>B</th><th>expected</th><th>actual result</th></tr>';
while ($cases)
{
    $a = array_shift($cases);
    $b = array_shift($cases);
#   echo '<hr>', outA($a), ' / ', outA($b) , ' -> ', outA($c);
    $expect = array_shift($cases);
    $result=m($a,$b);
    echo '<tr><td>',outA($a),'</td><td>',outA($b),'</td><td>', outA($expect), '</td><td>', outA($result),'</td></tr>';
}
echo '</table>';

ฉันไม่สามารถเข้าใจว่าทำไมคุณถึงทำให้มันไม่ง่าย$a&(!$b|$a[0]<$b[0])?$a:$bแทนที่จะเป็น${$a&(!$b|$a[0]<$b[0])?a:b}
JörgHülsermann

1
@ JörgHülsermann array_shiftพารามิเตอร์ถูกใช้โดยการอ้างอิง มันจะต้องเป็นตัวแปร การแสดงออกจะไม่ทำงาน
ติตัส


1

JavaScript - 133

function m(a,b){c=[];for(i=j=0;i<a.length&j<b.length;)c.push(a[i]<b[j]?a[i++]:b[j++]);return c.concat(a.slice(i)).concat(b.slice(j))}

วิธีการเช่นเดียวกับ OP


1

perl, 87 chars / perl 5.14, 78 + 1 = 79 ตัวอักษร

การใช้งานนี้จะครอบคลุมการอ้างอิงอาร์เรย์อินพุท นอกเหนือจากนั้นมันค่อนข้างตรงไปตรงมา: ในขณะที่อาร์เรย์ทั้งสองมีบางอย่างให้เลื่อนด้านล่างของทั้งสองออก จากนั้นส่งคืนบิตที่ผสานรวมกับบิตที่เหลืออยู่ (จะมีเพียงหนึ่งใน @ $ x หรือ @ $ y จะยังคงอยู่) perl5 ตรงขึ้น, 87 ตัวอักษร:

sub M{($x,$y,@o)=@_;push@o,$$x[0]>$$y[0]?shift@$y:shift@$x while@$x&&@$y;@o,@$x,@$y}

การใช้ Perl 5.14.0 และการเลื่อน arrayref แบบใหม่: 78 ตัวอักษร + 1 บทลงโทษถ่าน = 79 ตัวอักษร:

sub M{($x,$y,@o)=@_;push@o,shift($$x[0]>$$y[0]?$y:$x)while@$x&&@$y;@o,@$x,@$y}

*แทนที่จะ&&บันทึกเป็นไบต์ และยิ่งถ้าsub M{map{shift(!@$x+@$y*($$y[0]<$$x[0])?$y:$x)}map@$_,($x,$y)=@_}
2846289

@VadimR ว้าว การทำงานที่ดี ไปข้างหน้าและโพสต์ว่าถ้าคุณต้องการ - ฉันไม่เคยคิดที่จะทำเคล็ดลับแผนที่สองครั้งแทนที่จะผลักดันให้อาร์เรย์
skibrianski

1

Java: 144

ตรงนี้ค่อนข้างตรงไปตรงมา ฟังก์ชันที่ใช้สองอาร์เรย์และส่งคืนหนึ่งเวอร์ชันที่ผสานแล้ว golfed และไม่มี wrapper การคอมไพล์:

int[]m(int[]a,int[]b){int A=a.length,B=b.length,i,j;int[]c=new int[A+B];for(i=j=0;i+j<A+B;c[i+j]=j==B||i<A&&a[i]<b[j]?a[i++]:b[j++]);return c;}

Ungolfed (ด้วย wrapper ที่สามารถคอมไพล์และสามารถรันได้):

class M{
    public static void main(String[]args){
        int[]a=new int[args[0].split(",").length];
        int i=0;
        for(String arg:args[0].split(","))
            a[i++]=Integer.valueOf(arg);
        int[]b=new int[args[1].split(",").length];
        int j=0;
        for(String arg:args[1].split(","))
            b[j++]=Integer.valueOf(arg);
        int[]c=(new M()).m(a,b);
        for(int d:c)
            System.out.printf(" %d",d);
        System.out.println();
    }
    int[]m(int[]a,int[]b){
        int A=a.length,B=b.length,i,j;
        int[]c=new int[A+B];
        for(i=j=0;i+j<A+B;c[i+j]=j==B||i<A&&a[i]<b[j]?a[i++]:b[j++]);
        return c;
    }
}

ตัวอย่างการประหารชีวิต:

$ javac M.java
$ java M 10,11,12 0,1,2,20,30
 0 1 2 10 11 12 20 30
$ java M 10,11,12,25,26 0,1,2,20,30
 0 1 2 10 11 12 20 25 26 30

เคล็ดลับในการย่อให้สั้นจะได้รับการชื่นชม


1

สกาลา 97 ไบต์

โซลูชันแบบเรียกซ้ำด้วย O (n) ในการย่อโค้ดบางครั้งการดำเนินการทำได้โดยการเปลี่ยนพารามิเตอร์ที่สามารถเปลี่ยนได้ 2 ตัวคือ f (a, b) เรียก f (b, a)

type L=List[Int];def f(a:L,b:L):L=if(a==Nil)b else if(a(0)<=b(0))a(0)::f(a.drop(1),b) else f(b,a)

Ungolfed:

type L=List[Int]

def f(a:L, b:L) : L =
  if (a == Nil)
    b 
  else 
    if (a(0) <= b(0))
      a(0) :: f(a.drop(1), b) 
    else
      f(b,a)

ข้อยกเว้นถ้า a ไม่ว่างเปล่า แต่ b ว่างเปล่า
Dan Osipov

1

APL (32)

{⍺⍵∊⍨⊂⍬:⍺,⍵⋄g[⍋g←⊃¨⍺⍵],⊃∇/1↓¨⍺⍵}

คำอธิบาย:

{⍺⍵∊⍨⊂⍬                               if one or both of the arrays are empty
        :⍺,⍵                           then return the concatenation of the arrays
             ⋄g[⍋g←⊃¨⍺⍵]              otherwise return the sorted first elements of both arrays
                          ,⊃∇/        followed by the result of running the function with
                               1↓¨⍺⍵}  both arrays minus their first element

1

LISP, 117 ไบต์

อัลกอริทึมจะสิ้นสุดลงในn + 1การวนซ้ำโดยที่nความยาวของรายการที่สั้นที่สุดในอินพุต

(defun o(a b)(let((c(car a))(d(car b)))(if(null a)b(if(null b)a(if(< c d)(cons c(o(cdr a)b))(cons d(o a(cdr b))))))))

0

PYG (50)

def m(*a):
 while An(a):yield Mn(ItCo(a,a)).pop(0)

PYG (64 อีกครั้งหากไม่อนุญาตให้ใช้เครื่องกำเนิดไฟฟ้า):

def m(*a):
 r=[]
 while An(a):r+=[(Mn(ItCo(a,a)).pop(0)]
 return r

การปรับตัวของคำตอบหลามของฉัน


0

Python - 69 ไบต์

def m(A,B):
    C=[]
    while A and B:C+=[[A,B][A>B].pop(0)]
    return C+A+B

หากลำดับของอินพุทและเอาท์พุทลดลงสิ่งนี้อาจลดลงเหลือ61 ไบต์ :

def m(A,B):
    C=[]
    while A+B:C+=[[A,B][A<B].pop(0)]
    return C

และเพิ่มเติมลงไปที่45 ไบต์หากอนุญาตให้ใช้เครื่องกำเนิด

def m(A,B):
    while A+B:yield[A,B][A<B].pop(0)

นี่ไม่ใช่ O (n) แน่นอน .pop (0) และ + = เป็นทั้ง O (n) การดำเนินการที่คุณทำ O (n) ครั้ง
isaacg

ฉันไม่รู้ด้วยซ้ำจนกระทั่งตอนนี้ว่ารายการนั้นไม่ได้ถูกนำไปใช้เป็นรายการใน Pythonและpop(0)สามารถนำไปใช้ใน O (1) และ+=อย่างน้อยก็สามารถนำไปใช้ได้ดีกว่า O (n) (ดูลิงก์) วิธีแก้ปัญหาของคุณใช้+=(เช่นappendและextend) บ่อยเท่าของฉัน อย่างไรก็ตามทั้งหมดนี้คือคำถามการนำไปปฏิบัติ (เท่าที่ฉันรู้) ดังนั้นในการนำ Python ไปใช้ (รายการสมมติ) โดยที่รายการต่างๆถูกนำไปใช้เป็นรายการฟังก์ชันของฉันคือ O (n) ในที่สุดคำถามของคุณต้องการอัลกอริทึมเป็น O (n) และของฉันคือ
Wrzlprmft

ที่จริงแล้วผนวกและขยายจะดำเนินการแตกต่างกันในงูหลามกว่า + = คือ + = สร้างรายการใหม่ในขณะที่. ผนวกและ. ขยายแก้ไขรายการที่มีอยู่
isaacg

0

Perl 6: 53 ตัวอักษร

sub M(\a,\b){{shift a[0]>b[0]??b!!a}...{a^b},a[],b[]}

เปลี่ยนจากค่าใด ๆaหรือbมีค่าน้อยกว่าจนกระทั่งaXOR b( a^b) เป็นจริง จากนั้นส่งคืนสิ่งที่เหลืออยู่ให้แบน ( []) อาร์เรย์ลงในรายการ ( a[],b[])

สมมติว่าการขยับจากจุดเริ่มต้นของอาร์เรย์คือ O (n) กรณีที่แย่ที่สุดคือการเปรียบเทียบสองรายการและหนึ่งกะต่อองค์ประกอบดังนั้นอัลกอริทึมคือ O (n)


0

JavaScript (ES5) 90 86 90 ไบต์

function f(a,b){for(o=[];(x=a[0]<b[0]?a:b).length;)o.push(x.shift());return o.concat(a,b)}

แก้ไข: (90 -> 86) ย้าย ternary ลงในเงื่อนไข for loop ไอเดียถูกขโมยจากเดนนิส

แก้ไข: (86 -> 90) อาร์เรย์สตริงออกไปหล่อเป็นมันแบ่งO (n)ความต้องการ


0

Mathematica, 137 135

m[a_,b_]:=(l=a;Do[Do[If[b[[f]]<=l[[s]],(l=Insert[l,b[[f]],s];Break[]),If[s==Length@l,l=l~Append~b[[f]]]],{s,Length@l}],{f,Length@b}];l)

การป้อนข้อมูล:

m[{2,2,4,6,7,11},{1,2,3,3,3,3,7}]

เอาท์พุท:

{1, 2, 2, 2, 3, 3, 3, 3, 4, 6, 7, 7, 11}

Ungolfed:

mergeList[a_, b_] := (
    list = a;
    Do[
        Do[(
            If[
                b[[f]] <= list[[s]],
                (list = Insert[list, b[[f]], s]; Break[]),
                If[
                    s == Length@list,
                    list = list~Append~b[[f]]
                ]
        ]),
        {s, Length@list}
    ],
    {f, Length@b}
    ];
    list
)

อาจจะทำได้ดีกว่า


m[a:{x___,y_},b:{___,z_}]:=If[y<z,b~m~a,{x}~m~b~Join~{y}];{}~m~b_=b;
alephalpha

0

R, 80

วิธีการแก้ปัญหาเช่นเดียวกับใน Scala และภาษาอื่น ๆ ฉันไม่แน่ใจเกี่ยวกับ x [-1] คือ O (1)

f=function(a,b)if(length(a)){if(a[1]<=b[1])c(a[1],f(a[-1],b))else f(b,a)}else b

0

Mathematica, 104 ไบต์

Reap[{m,n}=Length/@{##};i=k=1;Do[If[k>n||TrueQ[#[[i]]<#2[[k]]],Sow@#[[i++]],Sow@#2[[k++]]],n+m]][[2,1]]&

ฟังก์ชั่นที่ไม่ระบุชื่อร้านค้าความยาวของทั้งสองรายการป้อนข้อมูลในตัวแปรmและnแล้วทวนของแต่ละDoวงSows องค์ประกอบของหนึ่งรายการ incrementing เคาน์เตอร์สำหรับรายการที่ ( iสำหรับครั้งแรกkครั้งที่สอง) โดยหนึ่ง หากหนึ่งในตัวนับเกินความยาวของรายการIfคำสั่งจะSowเป็นองค์ประกอบจากรายการอื่นเสมอ หลังจากn+mการดำเนินการองค์ประกอบทั้งหมดได้รับการดูแล Reapหรือค่อนข้างเป็นส่วนหนึ่ง[[2,1]]ของการส่งออกเป็นรายการขององค์ประกอบตามลำดับที่พวกเขาได้รับSow n

ฉันไม่แน่ใจว่า internals (กำลังเข้าถึงส่วนหนึ่งของรายการการO(1)ดำเนินการหรือไม่) แต่การกำหนดเวลาดูค่อนข้างเชิงเส้นบนเครื่องของฉันเกี่ยวกับความยาวของรายการอินพุต

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