เพิ่มความแตกต่างยกกำลังสอง


19

พิจารณาการเปลี่ยนแปลงของค่าจำนวนเต็มจากไป1 Nเช่นตัวอย่างนี้สำหรับN = 4:

[1, 3, 4, 2]

เราจะถือว่ารายการนี้เป็นวงจรเช่นนั้น1และ2ได้รับการปฏิบัติเหมือนติดกัน ปริมาณหนึ่งที่เราสามารถคำนวณได้สำหรับรายการดังกล่าวคือผลต่างกำลังสองรวมของค่าที่อยู่ติดกัน:

(1-3)² + (3-4)² + (4-2)² + (2-1)² = 10

Nงานของคุณคือการหาการเปลี่ยนแปลงซึ่งจะเพิ่มปริมาณนี้ให้เป็นจำนวนเต็มบวก ในกรณีของN = 4ตัวอย่างข้างต้นจะไม่เหมาะสมที่สุด (อันที่จริงแล้วเป็นเพียงเล็กน้อย) เราสามารถบรรลุผลต่างกำลังสองรวม18กับการเปลี่ยนแปลงต่อไปนี้ (รวมถึงการเปลี่ยนแปลงอื่น ๆ ):

[1, 4, 2, 3]

อัลกอริทึมของคุณต้องทำงานในเวลาพหุนาม (จากN) โดยเฉพาะอย่างยิ่งคุณไม่สามารถคำนวณความแตกต่างยกกำลังสองทั้งหมดของพีชคณิตทั้งหมดได้

คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่น, รับอินพุตผ่าน STDIN (หรือทางเลือกที่ใกล้เคียงที่สุด), อาร์กิวเมนต์บรรทัดคำสั่งหรืออาร์กิวเมนต์ของฟังก์ชันและส่งผลลัพธ์ผ่าน STDOUT (หรือทางเลือกที่ใกล้เคียงที่สุด), ค่าส่งคืนของฟังก์ชันหรือพารามิเตอร์

ผลลัพธ์อาจอยู่ในรูปแบบรายการแบบแบนหรือแบบสตริงที่สะดวกใด ๆ คุณอาจเลือกที่จะกลับรายการที่มีค่าจาก0การN-1แทนไป1N

ใช้กฎมาตรฐานของ

ทดสอบข้อมูล

มีวิธีการวิเคราะห์ที่ดีสำหรับปัญหานี้ เช่นโซลูชันที่ถูกต้องทั้งหมดN = 10จะเทียบเท่ากับรายการต่อไปนี้ (มากถึงกะกะและกลับรายการ):

[7, 5, 6, 4, 8, 2, 10, 1, 9, 3]

ฉันไม่ต้องการเปิดเผยมากไปกว่านั้น (แม้ว่ามันอาจจะเพียงพอที่จะเข้าใจรูปแบบ) ดังนั้นแทนที่จะให้ตัวอย่างเพิ่มเติมอีกคุณสามารถตรวจสอบได้ว่าผลลัพธ์ของคุณมีความแตกต่างยกกำลังสองทั้งหมดดังต่อไปนี้N:

N    Total squared difference

1                         0
2                         2
3                         6
4                        18
5                        36
6                        66
7                       106
8                       162
9                       232
10                      322
33                    11936
100                  333202
333                12308236
1000              333332002

นี่คือรายการ OEIS A064842 (ซึ่งมีการอ้างอิงถึงกระดาษพร้อมวิธีการแก้ไขปัญหานี้หากคุณติดอยู่)

คำตอบ:


7

เยลลี่, 24 21 15 14 10 9 ไบต์

RUĖµ«/€ị"

ในการคำนวณความแตกต่างยกกำลังสองทั้งหมดให้ผนวกµ_ṙ1$²Sกับรหัส ลองออนไลน์!

พื้นหลัง

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

ตัวอย่างเช่นสำหรับn = 8, 9เรามี

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
  ^   ^ ^   ^            ^   ^   ^   ^

(คาเร็ตทำเครื่องหมายจำนวนเต็มที่ต้องการสลับ) ซึ่งผลลัพธ์เป็น

1 7 3 5 4 6 2 8        1 8 3 6 5 4 7 2 9

หลังจากการแลกเปลี่ยน

วิธีหนึ่งในการบรรลุถึงการแลกเปลี่ยนเหล่านี้เป็นอิสระจากความเท่าเทียมกันของnมีดังนี้

เริ่มต้นด้วยการเขียนจำนวนเต็มตามลำดับจากน้อยไปหามากและเรียงจากมากไปน้อยหนึ่งรายการอยู่ด้านล่าง

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

สำหรับจำนวนเต็มแต่ละคู่ให้คำนวณค่าต่ำสุดของคู่ สิ่งนี้ทำให้ระยะห่างจากขอบที่ใกล้ที่สุดคือดัชนีจากด้านซ้ายหรือขวา (แล้วแต่จำนวนใดจะต่ำกว่า)

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

1 2 3 4 4 3 2 1        1 2 3 4 5 4 3 2 1

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

1   3     6   8        1   3   5   7   9
  7   5 4   2            8   6   4   2

นี่คือเอาต์พุตที่ต้องการ

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

RUĖµ«/€ị"    Main link. Input: n

R            Range. Yields [1, ..., n].
 U           Upend. Yields [n, ..., 1].
  Ė          Enumerate. Yields p := [[1, n], [2, n-1], ... [n-1, 2], [n, 1]].

   µ         Begin a new, monadic chain. Argument: p
     /       Reduce...
      €        each pair of p...
    «          by minimum.
        "    For each minimum and the corresponding pair of p:
       ị       Select the element at that index.
            Indices are modular and 1-based in Jelly, so this selects the first
            element if the minimum is odd, and the second one if it is even.

6

JavaScript (ES6), 52 ไบต์

n=>[...Array(n)].map((_,i)=>(i<n/2|n%2)^i%2?i+1:n-i)

บันทึกแล้ว 9 ไบต์ด้วย @Neil!

คำอธิบาย

วิธีการนี้จะกำหนดจำนวนที่ควรจะอยู่ที่ดัชนีที่iมีความยาวnมากกว่าการต่อผลลัพธ์กับอาร์เรย์ สิ่งนี้มีพื้นฐานจากการสังเกตต่อไปนี้ (ใช้n = 7เป็นตัวอย่าง):

  • เริ่มต้นด้วยตัวเลขต่ำสุดทางซ้ายและสูงสุดทางขวา: [ 1, 7 ]
  • สลับลำดับเพื่อให้ค่าต่ำสุดอยู่ทางขวาและค่าสูงสุดอยู่ทางซ้ายเพิ่มค่าต่ำสุดลดค่าสูงสุดและวางไว้ที่กึ่งกลางของอาร์เรย์:[ 1, 6, 2, 7 ]
  • ทำซ้ำจนกว่าการบรรจบกันสูงสุดและต่ำสุด: [ 1, 6, 3, 4, 5, 2, 7 ]

ตัวเลขที่สูงขึ้นและลดลงได้อย่างง่ายดายสามารถแสดงเป็นn-iและi+1ตามลำดับ

var solution =

n=>
  [...Array(n)] // create an array of length n
  .map((_,i)=>  // set each value of the array at index i
    (i<n/2      // if we're on the left side,
    |n%2)       // or we're on the right and n is odd, even i => lower, odd i => higher
    ^i%2?       // else even i => higher, odd i => lower
    i+1:n-i
  )
N = <input type="number" id="input" oninput="result.textContent=solution(+this.value)" />
<pre id="result"></pre>


อัลกอริทึมที่ดี; ฉันพยายามและล้มเหลวในการคิดสูตรเพื่อสร้างพวกเขาดังนั้นฉันจึงต้องใช้วิธีการที่น่าเกลียดของการผลักและไม่ขยับ อย่างไรก็ตามฉันสามารถทำให้ตรรกะของคุณง่ายขึ้น(i<n/2||n%2)^i%2?i+1:n-iได้
Neil

@Neil ว้าวฉันเพิ่งตื่นขึ้นมาจึงตัดสินใจที่จะมีสนามกอล์ฟนี้และมาพร้อมกับคุณแน่นอนตรรกะและเริ่มพิมพ์ออกไปทางขวาตามที่คุณโพสต์! บ้า ...
user81655

5

Python2, 105 98 ไบต์

บันทึกแล้ว 7 ไบต์ด้วยความคิดเห็นของ @Dennis

n=input()
r=([],[n/2+1])[n%2]
for i in range(n/2,0,-1):k=[n+1-i];r=([i]+r+k,k+r+[i])[i%2]
print r

รุ่นที่แก้ไขแล้ว 58 ไบต์

lambda n:[(n-i-1,i)[(i+(n,1)[i<n/2])%2]for i in range(n)]

ฉันเชื่อแล้วว่ามันควรเป็นไปได้ที่จะทำมันเป็นหนึ่งซับ แต่ตรรกะนั้นซับซ้อนเกินไปสำหรับฉัน เห็น JavaScript-answer โดย @ user81655 และ lambda-notation ใน @Dennis Python-answer ฉันได้ลองใหม่แล้ว

เงื่อนไขเท่ากับ

if i < n/2:
    i%2 != n%2
else:
    (i+1)%2

น่าเสียดายที่ความพยายามในการแปลงทั้งหมดจะช่วยประหยัดได้เพียงหนึ่งเดียวที่ไม่มีไบต์เปรียบเทียบกับการแปลโดยตรง(i<n/2or n%2)!=i%2ของจาวาสคริปต์


3
ยินดีต้อนรับสู่ Programming Puzzles & Code Golf! ดูเหมือนว่าจะเป็น Python 2 ดังนั้นคุณไม่จำเป็นต้องint()ใช้อินพุตโดยรอบ for...นอกจากนี้คุณยังสามารถใส่สำหรับร่างกายของวงในบรรทัดเดียวกันเป็น
Dennis

4

Python, 51 49 ไบต์

lambda n:[(i^min(i,~i%n)%-2)%n for i in range(n)]

ขอบคุณ @xnor สำหรับการเล่นกอล์ฟ 2 ไบต์!

ลองบนIdeone

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

ถ้าiเป็นตัวเลขใน[0, ... , n - 1]ดังนั้น~ i% n = - (i + 1)% n = - (i + 1) + n = (n - 1) - i , หมายความว่ามันแมป0ถึงn - 1 , 1ถึงn - 2และโดยทั่วไปรายการj thจากซ้ายไปยังj thจากด้านขวา

ดังที่อธิบายไว้ในคำตอบ Jelly ของฉันเราสามารถสร้างผลลัพธ์โดยการดูที่ค่าที่ต่ำกว่าในหมู่iและ~ i% nและเลือกiถ้ามันเป็นเลขคู่และ~ i% nถ้ามันแปลก เราบรรลุสิ่งนี้ดังนี้

  • หากขั้นต่ำแม้min(i,~i%n)%-2จะให้ผลผลิต0ดังนั้น XORing ผลกับฉันจะให้ฉันและคอมพิวเตอร์แบบโมดูโลตกค้างของnจะกลับฉัน

  • หากค่าต่ำสุดเป็นเลขคี่min(i,~i%n)%-2จะให้ค่า -1ดังนั้น XOR จะได้ผลลัพธ์ด้วยiจะให้~ iดังนั้นนิพจน์ทั้งหมดจะประเมินค่าเป็น~ i% nตามที่ต้องการ


(i^min(i,n+~i)%-2)%nคุณสามารถบันทึกคู่ของตัวอักษรด้วยการทำตามเงื่อนไขเป็น
xnor

นั่นไม่ใช่แค่สั้น แต่ฉลาดเท่านั้น ขอขอบคุณ!
เดนนิส

2

PHP, 77 76 51 50 49 ไบต์

ใช้การเข้ารหัส ISO 8859-1

การประกอบครึ่งแรกของอาร์เรย์เช่นนี้:

  • ตัวเลขคี่มีค่าดัชนี (1, 3, 5 .. )
  • เลขคู่มีค่าเท่ากับN+1-index(9, 7, 5)
  • ผลลัพธ์นี้ใน 1, 9, 3, 7, 5

สำหรับช่วงครึ่งหลังของอาร์เรย์ค่านอกสุดจะN+1รวมกันซึ่งหมายความว่าคุณสามารถรับค่าที่เหมาะสมจากN-[left value]ตำแหน่งที่ทราบค่าซ้ายแล้ว

for(;$k=$argv[1]-$j++;)echo" ",min($j,$k)%2?$j:$k;

ทำงานแบบนี้ (นี่แสดงให้เห็นถึงความแตกต่างกำลังสองทั้งหมด) ( -dเพิ่มเพื่อความสวยงามเท่านั้น):

php -d error_reporting=32757 -r 'for(;$k=$argv[1]-$j++;)echo~ß,$x[]=min($j,$k)%2?$j:$k;  for(;$c=$x[+$i++];)$b+=($c-($x[$i]?:$x[0]))**2;echo"\n$b\n";' 10
  • บันทึกไบต์ด้วยการปฏิเสธเงื่อนไขซ้าย / ขวาเพื่อให้สามารถประกอบไปด้วย ternary ที่สองได้โดยไม่ต้องใส่วงเล็บ
  • บันทึก 25 ไบต์โดยใช้อัลกอริทึมของ Dennis อย่างไร้ยางอาย
  • บันทึกไบต์โดยการกำจัดพื้นที่ที่ต้องการหลังจากนั้น echo
  • บันทึกไบต์โดยใช้เพื่อให้มีช่องว่าง

1

Python 2, 100

ฉันรู้ว่ามีคำตอบหลามอยู่แล้ว แต่ฉันคิดว่าฉันอาจทำสิ่งนี้แตกต่างออกไป

n=input();a=n%2;b=n/2;x=[b+1,b+a][a:]
for i in range(b+a-1):f=1-i%2*2;x=[x[-1]-f]+x+[x[0]+f]
print x

และเป็นพิเศษเพื่อทดสอบคะแนนรวม:

def t(x,n):return sum((x[i]-x[(i+1)%n])**2for i in range(n))

def t(x,n):return sum((x[i]-x[i-1])**2for i in range(n))ใช้การล้อมรอบโดยนัยของดัชนีลบและบันทึก 4 ไบต์ ฉันรู้ว่าไม่ใช่ส่วนหนึ่งของการแข่งขัน ;)
btwlf

1

CJam, 17 15 14 ไบต์

{,W%ee_::e<.=}

นี้เป็นฟังก์ชั่นที่ปรากฏจำนวนเต็มnจากสแต็คและผลักดันการเปลี่ยนแปลงของ[0 ... n-1]ในทางกลับกัน รหัสที่ใช้วิธีการเดียวกับคำตอบของวุ้นของฉัน

ลองออนไลน์!

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

,W%ee_::e<.=    Function body. Stack: N

,               Turn N into [0 ... N-1].
 W%             Reverse to push [N-1 ... 0].
   ee           Enumerate. This pushes [[0 N-1] [1 N-2] ... [N-2 1] [N-1 0]].
     _          Push a copy of the array of pairs.
      ::e<      Reduce each pair by minimum.
          .=    Vectorized selection.
                For the Ith minimum M, select the Mth element of the Ith pair.
                Indices are modular and 0-based in CJam, so this selects the first
                element if the minimum is even, and the second one if it is odd.

1

LISP, 86 ไบต์

(defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

อินพุตของฟังก์ชั่นอนุญาตให้เลือกค่าเริ่มต้น (m) และค่าสิ้นสุด (n) ของลำดับ

สำหรับการทดสอบฟังก์ชั่นตามตัวอย่างที่มีให้ n ถูกกำหนดเป็น N และ m ถึง 1

นี่คือรหัสเพื่อทดสอบฟังก์ชั่น:

    (defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

(defun sq (c)
    (apply #'+ (mapcar #'(lambda(x y) (* (- x y) (- x y))) c (append (cdr c) (list (car c))))))

(format t "N~20TSequence~50TSquared Difference~%")
(mapcar #'(lambda (x)(format t "~S~20T~S~50T~S~%" x (g x 1) (sq (g x 1)))) '(1 2 3 4 5 6 7 8 9 10 33 100 333 1000))

ลองใช้กับIdeone !


1

Julia, 39 ไบต์

n->map(i->min(i-1,n-i)%2>0?n-~-i:i,1:n)

พิมพ์นี้การเปลี่ยนแปลงของแบบ 1: n การเรียงสับเปลี่ยนของ0: n-1ไม่มีค่าใช้จ่ายและไม่บันทึกไบต์:

n->map(i->min(i,n+~i)%2>0?i:n+~i,0:n-1)

รุ่นนี้สุดท้ายคือพอร์ตโดยตรงของคำตอบหลามของฉัน


0

ES6, 77 ไบต์

n=>[...Array(n)].map(_=>r[++i&2?"push":"unshift"](i&1?n--:++j),i=j=0,r=[])&&r

i&1ตัวอย่างตัวเลขจากสุดขั้วไปตรงกลาง การi&2เพิ่มลงในจุดเริ่มต้นหรือจุดสิ้นสุดของผลลัพธ์เป็นคู่


0

R, 117 86 ไบต์

z=1:(n<-scan());a=pmin(z,n:1);for(i in seq(2,,2,n%/%2))z[b]=z[rev(b<-which(a==i,T))];z

แก้ไขแทนที่ buggy รุ่นยาวด้วยการใช้อัลกอริทึมของ @Dennis 'Jelly

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