Regex (ECMAScript รส), 392 358 328 224 206 165 ไบต์
เทคนิคที่จำเป็นในการเล่นเพื่อจับคู่หมายเลข Fibonacci กับ ECMAScript regex (ในภาษาเดียว) เป็นหนทางไกลจากวิธีที่ทำได้ดีที่สุดในรสชาติ Regex อื่น ๆ การขาดการตอบโต้กลับ / ซ้อนซ้ำหรือการเรียกซ้ำหมายความว่ามันเป็นไปไม่ได้ที่จะนับหรือเก็บผลรวมของการทำงานใด ๆ โดยตรง การขาดการมองดูทำให้บ่อยครั้งเป็นสิ่งที่ท้าทายแม้จะมีพื้นที่เพียงพอที่จะทำงาน
ปัญหามากมายจะต้องได้รับการติดต่อจากมุมมองที่แตกต่างกันอย่างสิ้นเชิงและดูเหมือนจะแก้ไม่ได้จนกว่าจะถึงความเข้าใจที่สำคัญบางอย่าง มันบังคับให้คุณใช้เครือข่ายที่กว้างขึ้นมากในการค้นหาว่าคุณสมบัติทางคณิตศาสตร์ของตัวเลขที่คุณทำงานด้วยอาจจะถูกใช้เพื่อสร้างปัญหาเฉพาะที่แก้ไขได้
ในเดือนมีนาคม 2014 นี่คือสิ่งที่เกิดขึ้นสำหรับหมายเลขฟีโบนักชี เมื่อมองไปที่หน้าวิกิพีเดียในตอนแรกฉันไม่สามารถหาวิธีได้แม้ว่าจะมีทรัพย์สินหนึ่งที่ดูเหมือนจะยั่วเย้า จากนั้นนักคณิตศาสตร์teukon ได้สรุปวิธีการที่ทำให้เห็นได้ชัดว่ามันเป็นไปได้ที่จะทำโดยใช้คุณสมบัตินั้นพร้อมกับอีกอันหนึ่ง เขาลังเลที่จะสร้าง regex ปฏิกิริยาของเขาเมื่อฉันไปข้างหน้าและทำมัน:
คุณบ้า! ... ฉันคิดว่าคุณอาจทำสิ่งนี้
เช่นเดียวกับ ECMAScript unary math regex อื่น ๆ ของฉันโพสต์ฉันจะให้คำเตือน:ฉันขอแนะนำให้เรียนรู้วิธีการแก้ปัญหาทางคณิตศาสตร์ unary ใน ECMAScript regex มันเป็นการเดินทางที่น่าสนใจสำหรับฉันและฉันไม่ต้องการที่จะทำลายมันสำหรับใครก็ตามที่อาจต้องการลองด้วยตัวเองโดยเฉพาะผู้ที่มีความสนใจในทฤษฎีจำนวน ดูโพสต์นั้นสำหรับรายการของปัญหาแนะนำที่ติดแท็กสปอยเลอร์อย่างต่อเนื่องเพื่อแก้ปัญหาทีละคน
ดังนั้นไม่ได้อ่านเพิ่มเติมใด ๆ ถ้าคุณไม่ต้องการบางมายากล regex เอกมากมายสำหรับคุณ หากคุณต้องการถ่ายภาพเพื่อหาเวทมนตร์นี้ด้วยตัวเองฉันขอแนะนำให้เริ่มต้นด้วยการแก้ปัญหาบางอย่างใน ECMAScript regex ดังที่ระบุไว้ในโพสต์ที่ลิงก์ด้านบน
ความท้าทายที่ผมเริ่มประสบจำนวนเต็มบวกx เป็นจำนวนฟีโบนักชีถ้าและเพียง 5x ถ้า2 + 4 และ / หรือ 5x 2 - 4 เป็นตารางที่สมบูรณ์ แต่ไม่มีที่ว่างให้คำนวณใน regex พื้นที่เดียวที่เราต้องทำงานคือจำนวนตัวเอง เราไม่มีที่ว่างพอที่จะคูณด้วย 5 หรือใช้สี่เหลี่ยมจัตุรัสทั้งคู่
แนวคิดของ teukon เกี่ยวกับวิธีแก้ไข ( โพสต์ดั้งเดิมที่นี่ ):
regex แสดงด้วยสตริงของฟอร์ม^x*$
ให้ z เป็นความยาว ตรวจสอบว่า z เป็นหนึ่งในไม่กี่หมายเลขแรกของฟีโบนัชชีด้วยมือ (มากถึง 21 ควรทำ) ถ้าไม่ใช่:
- อ่านตัวเลขสองสามตัว a <b เช่นว่า b ไม่มากกว่า 2a
- ใช้ไปข้างหน้ามอง Aheads ที่จะสร้าง2 , AB และข2
- ยืนยันว่า 5a 2 + 4 หรือ 5a 2 - 4 เป็นสี่เหลี่ยมจัตุรัสที่สมบูรณ์แบบ (ดังนั้นต้องเป็น F n-1สำหรับบาง n)
- ยืนยันว่า 5b 2 + 4 หรือ 5b 2 + 4 เป็นสี่เหลี่ยมจัตุรัสที่สมบูรณ์แบบ (ดังนั้น b ต้องเป็น F n )
- ตรวจสอบว่า z = F 2n + 3หรือ z = F 2n + 4โดยใช้2 , ab, และ b 2 ที่สร้างไว้ก่อนหน้าและตัวตน:
- F 2n-1 = F n 2 + F n-1 2
- F 2n = (2F n-1 + F n ) F n
ในช่วงสั้น ๆ : อัตลักษณ์เหล่านี้ช่วยให้เราสามารถลดปัญหาของการตรวจสอบว่าเป็นจำนวนที่กำหนดจะ Fibonacci เพื่อการตรวจสอบว่าคู่ของมากขนาดเล็กจำนวนมากมีฟีโบนักชี พีชคณิตเล็กน้อยจะแสดงให้เห็นว่าถ้ามีขนาดใหญ่พอที่ n (n = 3 ควรทำ), F 2n + 3 > F n + 5F n 2 + 4 ดังนั้นจึงควรมีที่ว่างเพียงพอ
และนี่คือการจำลองของอัลกอริทึมใน Cซึ่งฉันเขียนเป็นแบบทดสอบก่อนที่จะนำไปใช้ใน regex
ดังนั้นโดยไม่มีความกังวลใจต่อไปนี่คือ regex:
^((?=(x*).*(?=x{4}(x{5}(\2{5}))(?=\3*$)\4+$)(|x{4})(?=xx(x*)(\6x?))\5(x(x*))(?=(\8*)\9+$)(?=\8*$\10)\8*(?=(x\2\9+$))(x*)\12)\7\11(\6\11|\12)|x{0,3}|x{5}|x{8}|x{21})$
ลองออนไลน์!
และเวอร์ชั่นที่พิมพ์สวยและมีความคิดเห็น:
^(
(?=
(x*) # \2+1 = potential number for which 5*(\2+1)^2 ± 4
# is a perfect square; this is true iff \2+1 is a Fibonacci
# number. Outside the surrounding lookahead block, \2+1 is
# guaranteed to be the largest number for which this is true
# such that \2 + 5*(\2+1)^2 + 4 fits into the main number.
.*
(?= # tail = (\2+1) * (\2+1) * 5 + 4
x{4}
( # \3 = (\2+1) * 5
x{5}
(\2{5}) # \4 = \2 * 5
)
(?=\3*$)
\4+$
)
(|x{4}) # \5 = parity - determined by whether the index of Fibonacci
# number \2+1 is odd or even
(?=xx (x*)(\6 x?)) # \6 = arithmetic mean of (\2+1) * (\2+1) * 5 and \8 * \8,
# divided by 2
# \7 = the other half, including remainder
\5
# require that the current tail is a perfect square
(x(x*)) # \8 = potential square root, which will be the square root
# outside the surrounding lookahead; \9 = \8-1
(?=(\8*)\9+$) # \10 = must be zero for \8 to be a valid square root
(?=\8*$\10)
\8*
(?=(x\2\9+$)) # \11 = result of multiplying \8 * (\2+1), where \8 is larger
(x*)\12 # \12 = \11 / 2; the remainder will always be the same as it
# is in \7, because \8 is odd iff \2+1 is odd
)
\7\11
(
\6\11
|
\12
)
|
x{0,3}|x{5}|x{8}|x{21} # The Fibonacci numbers 0, 1, 2, 3, 5, 8, 21 cannot be handled
# by our main algorithm, so match them here; note, as it so
# happens the main algorithm does match 13, so that doesn't
# need to be handled here.
)$
ขั้นตอนวิธีการคูณไม่ได้อธิบายในความคิดเห็นเหล่านั้น แต่จะมีการอธิบายสั้น ๆ ในวรรคของฉันตัวเลขมากมายโพสต์ regex
ฉันรักษา Fibonacci regex หกรุ่น: สี่วงล้อนั้นจากความยาวสั้นที่สุดไปจนถึงความเร็วที่เร็วที่สุดและใช้อัลกอริทึมที่อธิบายข้างต้นและอีกสองรุ่นที่ใช้อัลกอริทึมที่แตกต่างกันเร็วกว่า แต่ยาวกว่ามาก ดัชนี Fibonacci เป็นการจับคู่ (อธิบายว่าอัลกอริทึมที่นี่อยู่นอกเหนือขอบเขตของโพสต์นี้ แต่มันอธิบายไว้ในสรุปสาระสำคัญเดิม ) ฉันไม่คิดว่าฉันจะรักษา regex รุ่นที่คล้ายกันจำนวนมากอีกครั้งเพราะในขณะที่ฉันทำการทดสอบทั้งหมดใน PCRE และ Perl แต่เครื่องมือ regex ของฉัน เร็วพอที่ความกังวลเรื่องความเร็วจะไม่สำคัญอีกต่อไป (และถ้าสิ่งก่อสร้างเฉพาะทำให้คอขวดฉันสามารถเพิ่มการเพิ่มประสิทธิภาพสำหรับมัน) - แม้ว่าฉันอาจจะคงรุ่นที่เร็วที่สุดหนึ่งและอีกหนึ่งรุ่นที่สั้นที่สุดถ้าความแตกต่าง ความเร็วมีขนาดใหญ่พอ
"คืนค่าดัชนี Fibonacci ลบด้วย 1 ในรูปแบบการแข่งขัน" (ไม่ได้ตีกอล์ฟมาก):
ลองออนไลน์!
ทุกรุ่นอยู่ใน GitHub ที่มีประวัติความเป็นมาเต็มรูปแบบของการเพิ่มประสิทธิภาพกอล์ฟ:
regex สำหรับการจับคู่หมายเลข Fibonacci - สั้น, เร็ว 0.txt (สั้นที่สุด แต่ช้าที่สุด, ในกระทู้นี้)
regex สำหรับการจับคู่หมายเลข Fibonacci - สั้น, ความเร็ว 1.txt
regex สำหรับการจับคู่หมายเลข Fibonacci - สั้น, ความเร็ว 2.txt
regex สำหรับ การจับคู่หมายเลขฟีโบนักชี - สั้น, ความเร็ว 3.txt
regex สำหรับการจับคู่หมายเลขฟีโบนักชี - เร็วที่สุด. เร็กซ์
regex สำหรับการจับคู่หมายเลขฟีโบนักชี - return index.txt