ค้นหาผลรวมของระยะทางที่ใกล้ที่สุด


10

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

ตัวอย่าง:

X = (1 5,9)
Y = (3,4,7)

ระยะทางคือ 2 + 1 + 2

X = (1,2,3)
Y = (0,8)

ระยะทางคือ 1 + 2 + 3

รหัสของคุณสามารถป้อนข้อมูลในวิธีที่สะดวก

ข้อ จำกัด หลักคือรหัสของคุณจะต้องทำงานในเวลาเชิงเส้นในผลรวมของความยาวของสองอาร์เรย์ . (คุณสามารถสันนิษฐานได้ว่าการเพิ่มจำนวนเต็มสองจำนวนต้องใช้เวลาคงที่)


เราสามารถใช้รายการหรือสตรีมแทนอาร์เรย์ได้หรือไม่
Ad Hoc Garf Hunter

@ CatWizard ใช่คุณทำได้!
Anush

1
เป็นวิธีการ1 + 2 + 3ที่ได้มาจากX = (1,2,3)และY = (0,8)?
guest271314

1
@ guest271314 จำนวนที่ใกล้เคียงที่สุดสองแต่ละ1, 2และ3ในมีY 0ดังนั้นความแตกต่าง1-0, ,2-0 3-0
dylnan

1
@FreezePhoenix เนื่องจากทั้งสองรายการเรียงลำดับคุณสามารถทำได้ใน O (n + m) เนื่องจากคุณวนซ้ำรายการไปที่แต่ละองค์ประกอบหนึ่งครั้งและตราบใดที่คุณติดตามองค์ประกอบY jใกล้เคียงกับX iคุณสามารถ ตรวจสอบกับY jและY j + 1เนื่องจากหนึ่งในนั้นใกล้เคียงกับX i + 1XYjXiYjYj+1Xi+1
Giuseppe

คำตอบ:


6

Haskell , 70 64 ไบต์

a%b=abs$a-b
x@(a:b)#y@(c:d)|e:_<-d,a%c>a%e=x#d|1>0=a%c+b#y
_#_=0

ลองออนไลน์!

คำอธิบาย

ก่อนอื่นเรานิยาม(%)ว่าเป็นความแตกต่างที่แน่นอนระหว่างตัวเลขสองตัว จากนั้นเรากำหนด(#)ให้เป็นฟังก์ชั่นที่น่าสนใจ ในบรรทัดแรกเราจับคู่เมื่อรายการทั้งสองไม่ว่างเปล่า:

x@(a:b)#(c:d:e)

เกี่ยวกับกรณีแรกของเราจากที่นี่เราผูกdไปกับe:_ e:_<-dเพื่อให้แน่ใจว่านี้เป็นไม่ว่างเปล่าและชุดมันเป็นองค์ประกอบแรกที่จะde

แล้วถ้าองค์ประกอบที่สองของ ( ) เป็นผู้ใกล้ชิดกว่าครั้งแรก ( ) เพื่อองค์ประกอบแรกของX ( ) เรากลับเอาองค์ประกอบแรกของYและเรียกอีกแบบเดียวกับXYecXax#dYX

หากเราตรงกับรูปแบบ แต่ไม่ผ่านเงื่อนไขที่เราทำ:

a%c+b#y

XX

0XY

O(|X|+|Y|)

Haskell , 34 ไบต์

O(|X|×|Y|)

x#y=sum[minimum$abs.(z-)<$>y|z<-x]

ลองออนไลน์!


ฉันชี้แจงในคำถามที่เราสามารถสันนิษฐานได้ว่าการเพิ่มจำนวนเต็มสองจำนวนต้องใช้เวลาคงที่
Anush

2

Python 2 , 124 120 bytes

X,Y=input()
i=j=s=0
while i<len(X):
 v=abs(Y[j]-X[i])
 if j+1<len(Y)and v>=abs(Y[j+1]-X[i]):j+=1
 else:s+=v;i+=1
print s

ลองออนไลน์!

บันทึก 4 ไบต์ด้วยการย้ายไปยังโปรแกรมและฟังก์ชั่น

การตอบสนองข้อ จำกัด ด้านเวลาที่ซับซ้อนเป็นไปได้เนื่องจากมีการเรียงลำดับรายการทั้งสอง โปรดทราบว่าแต่ละครั้งรอบลูปนั้นจะiถูกเพิ่มหรือjจะเพิ่มขึ้น ดังนั้นการวนซ้ำจะดำเนินการในlen(X)+len(Y)เวลาส่วนใหญ่


ฉันชี้แจงในคำถามที่เราสามารถสมมติว่าการเพิ่มจำนวนเต็มสองจำนวนต้องใช้เวลาคงที่
Anush

1

C (gcc), 82 ไบต์

n;f(x,y,a,b)int*x,*y;{for(n=0;a;)--b&&*x*2-*y>y[1]?++y:(++b,--a,n+=abs(*x++-*y));}

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

ลองออนไลน์!

n;                     // define sum as an integer
f(x,y,a,b)             // function taking two arrays and two lengths
int*x,*y;              // use k&r style definitions to shorten function declaration
{
 for(n=0;              // initialize sum to 0
 a;)                   // keep looping until x (the first array) runs out
                       // we'll decrement a/b every time we increment x/y respectively
 --b&&                 // if y has ≥1 elements left (b>1, but decrements in-place)...
 *x*2-*y>y[1]?         // ... and x - y > [next y] - x, but rearranged for brevity...
 ++y:                  // increment y (we already decremented b earlier);
 (++b,                 // otherwise, undo the in-place decrement of b from before...
 --a,n+=abs(*x++-*y))  // decrement a instead, add |x-y| to n, and then increment x
;}

หมายเหตุบางส่วน:

  • แทนที่จะจัดทำดัชนีลงในอาร์เรย์การเพิ่มตัวชี้และการยกเลิกการลงทะเบียนโดยตรงจะบันทึกจำนวนไบต์ที่เพียงพอเพื่อให้คุ้มค่า ( *xvs x[a]และy[1]vs y[b+1])

  • --b&&เงื่อนไขการตรวจสอบb>1ในทางอ้อม - ถ้าbเป็น1ก็จะมีการประเมินเป็นศูนย์ เนื่องจากการปรับเปลี่ยนนี้bเราไม่จำเป็นต้องเปลี่ยนแปลงในสาขาแรกของไตรภาค (ซึ่งก้าวหน้าy) แต่เราจำเป็นต้องเปลี่ยนกลับในวินาที (ซึ่งก้าวหน้าx)

  • ไม่returnจำเป็นต้องมีคำสั่งเพราะเวทมนตร์สีดำ (ฉันคิดว่าเป็นเพราะคำสั่งสุดท้ายที่ประเมินจะเป็นn+=...นิพจน์เสมอซึ่งจะใช้การลงทะเบียนเดียวกับที่ใช้สำหรับค่าส่งคืน)


0

Ruby, 88 ไบต์

->(p,q){a=q.each_cons(2).map{|a|a.sum/a.size}
x=a[0]
p.sum{|n|x=a.pop if n>x
(n-x).abs}}

ลองออนไลน์!

นอกจากนี้เพื่อความสนุกฟังก์ชั่นนิรนามที่สั้นกว่าซึ่งไม่ค่อยตรงตามข้อ จำกัด ด้านความซับซ้อน:

->(a,b){a.map{|x|x-b.min_by{|y|(x-y).abs}}.sum}

คุณช่วยอธิบายด้วยวิธีง่าย ๆ ว่ารหัสนี้ทำงานอย่างไร ฉันไม่สามารถบอกได้ว่ามันทำงานในเวลาเชิงเส้นหรือไม่
Anush

2
[5, 6], [0, 1, 5]นี้ล้มเหลวในกรณีที่การทดสอบครั้งแรกในคำถามเช่นเดียวกับปัจจัยการผลิตเช่น
Doorknob

0

JavaScript (Node.js) , 80 ไบต์

x=>g=(y,i=0,j=0,v=x[i],d=v-y[j],t=d>y[j+1]-v)=>1/v?g(y,i+!t,j+t)+!t*(d>0?d:-d):0
  • มันทำงานใน O (| X | + | Y |): การเรียกซ้ำทุกครั้งใน O (1) และจะเรียกซ้ำ | X | + | Y | ครั้ง
    • x, yถูกส่งผ่านโดยการอ้างอิงซึ่งไม่ได้คัดลอกเนื้อหา
  • 1/vเป็นเท็จถ้าx[i]อยู่นอกระยะความจริงเป็นอย่างอื่น
  • t-> d>y[j+1]-v-> v+v>y[j]+y[j+1]เป็นเท็จตราบเท่าที่เงื่อนไขต่อไปนี้เป็นไปตาม และซึ่งหมายความว่าy[j]เป็นจำนวนที่ใกล้เคียงกับvในy
    • vน้อยกว่า(y[j]+y[j+1])/2หรือ
    • y[j+1]อยู่นอกช่วงซึ่งจะแปลงเป็นNaNและเปรียบเทียบกับNaNผลผลิตfalse
      • นั่นเป็นเหตุผลที่เราไม่สามารถพลิก>สัญญาณเพื่อบันทึกอีก 1 ไบต์
  • tเป็นค่าบูลีนเสมอและ*แปลงเป็น0/ 1ก่อนการคำนวณ

ลองออนไลน์!


0

Mathematica ขนาด 40 ไบต์

x = {1, 5, 9};
y = {3, 4, 7};

Norm[Flatten[Nearest[y] /@ x] - x]

หากคุณต้องสร้างโปรแกรมเต็มรูปแบบด้วยอินพุต:

f[x_,y_]:= Norm[Flatten[Nearest[y] /@ x] - x]

นี่คือระยะเวลาสูงสุด 1,000,000 คะแนน (สุ่มทุก 10,000) สำหรับy:

ป้อนคำอธิบายรูปภาพที่นี่

ใกล้กับเส้น


1
คำตอบนี้เป็นข้อมูลโค้ดเนื่องจากข้อมูลที่คุณป้อนนั้นเป็นตัวแปรที่มีอยู่แล้ว คุณควรจัดรูปแบบให้เป็นแบบย่อยหรือแบบเต็มโปรแกรม
Ad Hoc Garf Hunter

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