เรติน่า , 66 63 45 43 36 ไบต์
^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$
แม้จะมีชื่อเรื่องว่า Retina แต่นี่เป็นเพียง regex. NET แบบธรรมดาซึ่งยอมรับการแสดงตัวเลข Loeschian
อินพุต 999 และ 1,000 ทำได้ดีในเสี้ยววินาที
ลองออนไลน์! (บรรทัดแรกเปิดใช้งานชุดทดสอบที่แยกบรรทัดด้วยฟีดและอีกสองรายการจะดูแลการแปลงเป็นเอกเพื่อความสะดวก)
คำอธิบาย
วิธีการแก้ปัญหานั้นขึ้นอยู่กับการจำแนกประเภทที่อินพุตสามารถเขียนได้ทั้งแบบi*i + j*(i + j)
บวกi
และไม่ลบj
(เนื่องจากเราไม่ต้องจัดการอินพุต0
) และนั่นn*n
เป็นเพียงผลรวมของn
จำนวนเต็มคี่แรก การตีกอล์ฟนี่เป็นแบบฝึกหัดที่น่าสนใจในการอ้างอิงล่วงหน้า
"การอ้างอิงไปข้างหน้า" คือเมื่อคุณใส่ backreference ภายในกลุ่มที่อ้างอิง แน่นอนว่าใช้ไม่ได้เมื่อกลุ่มถูกใช้เป็นครั้งแรกเนื่องจากยังไม่มีสิ่งใดที่จะต้องอ้างอิงกลับ แต่ถ้าคุณใส่สิ่งนี้ไว้ในลูป ในทางกลับกันคุณสามารถสร้างการจับภาพที่ใหญ่ขึ้นด้วยการวนซ้ำแต่ละครั้ง สิ่งนี้สามารถใช้เพื่อสร้างรูปแบบที่กะทัดรัดมากสำหรับสิ่งต่าง ๆ เช่นหมายเลขสามเหลี่ยมสี่เหลี่ยมและหมายเลขฟีโบนักชี
ยกตัวอย่างเช่นการใช้ความจริงที่ว่าสแควร์สเป็นเพียงผลรวมของn
จำนวนเต็มคี่แรกเราสามารถจับคู่อินพุตสแควร์แบบนี้:
(^.|..\1)+$
ในการทำซ้ำครั้งแรก..\1
ไม่สามารถทำงานได้เพราะ\1
ยังไม่มีคุณค่า ดังนั้นเราจึงเริ่มต้นด้วยการจับตัวเดียวในกลุ่ม^.
1
ในการวนซ้ำครั้งต่อไปจะ^.
ไม่ตรงกันอีกต่อไปเนื่องจากสมอ แต่ตอนนี้..\1
ใช้ได้ มันตรงกับตัวละครสองตัวมากกว่าซ้ำก่อนหน้านี้และปรับปรุงการจับภาพ วิธีนี้เราจับคู่กับการเพิ่มตัวเลขคี่รับสี่เหลี่ยมหลังจากการวนซ้ำแต่ละครั้ง
ตอนนี้น่าเสียดายที่เราไม่สามารถใช้เทคนิคนี้ตามที่เป็นอยู่ หลังจากจับคู่i*i
เราจำเป็นต้องได้รับเป็นอย่างดีเพื่อให้เราสามารถคูณด้วยi
j
ง่าย ( แต่ยาว) วิธีการทำเช่นนี้คือการใช้ประโยชน์จากความจริงที่ว่าการจับคู่i*i
ยิงi
ซ้ำเพื่อให้เราได้บันทึกสิ่งที่อยู่ในกลุ่มi
1
ตอนนี้เราสามารถใช้กลุ่มที่สมดุลเพื่อดึงข้อมูลนี้ออกi
มาได้ แต่อย่างที่บอกว่าแพง
แต่ฉันคิดหาวิธีที่แตกต่างในการเขียน "ผลรวมของจำนวนเต็มคี่ที่ต่อเนื่องกัน" นี้ซึ่งให้ผลi
ในกลุ่มการจับที่ท้ายที่สุด แน่นอนi
เลขคี่ TH 2i-1
เป็นเพียง สิ่งนี้ทำให้เรามีวิธีเพิ่มการอ้างอิงไปข้างหน้าเพียง 1 ครั้งในการทำซ้ำแต่ละครั้ง นั่นคือส่วนนี้:
^()(\1(?<1>.\1))+
สิ่งนี้()
จะผลักการจับภาพที่ว่างเปล่าไปยังกลุ่ม1
(เริ่มต้นi
ไปที่0
) นี่เป็น^.|
วิธีที่ง่ายกว่าวิธีแก้ปัญหาข้างต้น แต่การใช้งาน|
ในกรณีนี้จะค่อนข้างยุ่งยาก
(\1(?<1>.\1))
แล้วเรามีวงหลัก \1
ตรงกับก่อนหน้านี้i
, (?<1>.\1)
จากนั้นปรับปรุงกลุ่มด้วย1
i+1
ในแง่ของใหม่ i
เราเพิ่งจับคู่2i-1
ตัวละคร สิ่งที่เราต้องการ
เมื่อเราทำเสร็จแล้วเราได้จับคู่สี่เหลี่ยมจตุรัสi*i
และกลุ่ม1
ยังคงมีi
ตัวละครอยู่
ส่วนที่สองนั้นอยู่ใกล้กับการจับคู่สี่เหลี่ยมจัตุรัสอย่างง่ายที่ฉันได้แสดงไว้ด้านบน ตอนนี้เราไม่สนใจ backreference 1
:
(.(?(4).\1))*
นี่เป็นพื้นเดียวกัน(^.|..\4)*
ยกเว้นว่าเราไม่สามารถใช้^
เพราะเราไม่ได้อยู่ที่จุดเริ่มต้นของสตริง แต่เราใช้เงื่อนไขเพื่อจับคู่เพิ่มเติม.\1
เฉพาะเมื่อเราใช้กลุ่ม4
แล้ว แต่ในความเป็นจริงมันก็เหมือนกัน j*j
นี้จะช่วยให้เรา
สิ่งเดียวที่ขาดหายไปคือj*i
คำศัพท์ เรารวมสิ่งนี้เข้ากับj*j
โดยใช้ประโยชน์จากความจริงที่ว่าการj*j
คำนวณยังต้องใช้j
การวนซ้ำ ดังนั้นสำหรับแต่ละซ้ำเรายังก้าวไปเคอร์เซอร์โดยมีi
\1
เราแค่ต้องแน่ใจว่าจะไม่เขียนลงในกลุ่ม4
เพราะมันจะยุ่งกับตัวเลขคี่ที่ต่อเนื่องกัน นั่นเป็นวิธีที่เรามาถึง:
(\1(.(?(4).\1)))*