จับคู่สตริงที่มีความยาวเป็นกำลังสี่


28

ภายในขอบเขตของคำถามนี้ให้เราพิจารณาเฉพาะสตริงที่ประกอบด้วยอักขระxซ้ำจำนวนครั้งโดยพลการ

ตัวอย่างเช่น:

<empty>
x
xx
xxxxxxxxxxxxxxxx

(อันที่จริงมันไม่จำเป็นต้องเป็นx- ตัวละครใด ๆ ได้ดีตราบใดที่สายอักขระทั้งหมดมีอักขระ 1 ชนิดเท่านั้น)

เขียน regex ในรูปแบบ regex ที่คุณเลือกเพื่อจับคู่สตริงทั้งหมดที่มีความยาวเท่ากับ4สำหรับจำนวนเต็มจำนวนที่ไม่เป็นลบ n (n> = 0) ตัวอย่างเช่นสตริงที่มีความยาว 0, 1, 16, 81 เป็นต้นถูกต้อง ส่วนที่เหลือไม่ถูกต้อง

เนื่องจากข้อ จำกัด ทางเทคนิคค่าของ n ที่มากกว่า 128 จึงยากที่จะทดสอบ อย่างไรก็ตาม regex ของคุณควรทำงานอย่างมีเหตุผลโดยไม่คำนึงถึง

โปรดทราบว่าคุณไม่ได้รับอนุญาตให้ใช้รหัสโดยอำเภอใจใน regex ของคุณ (สำหรับผู้ใช้ Perl) อนุญาตให้ใช้ไวยากรณ์อื่น ๆ (ดูรอบ ๆ ย้อนกลับอ้างอิง ฯลฯ )

โปรดระบุคำอธิบายสั้น ๆ เกี่ยวกับแนวทางการแก้ไขปัญหาของคุณ

(โปรดอย่าวางคำอธิบายไวยากรณ์ regex ที่สร้างขึ้นอัตโนมัติเนื่องจากไม่มีประโยชน์)


"xx" ไม่ถูกต้องใช่ไหม
Kendall Frey

@KendallFrey: ไม่ มันไม่ถูกต้อง
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@nhahtdh คุณคิดว่ามีคำตอบที่เป็นไปได้หรือไม่?
xem

1
@Timwi: ใช่ Java, PCRE (อาจเป็น Perl แต่ยังไม่สามารถทดสอบได้),. NET แม้ว่าฉันจะไม่ทำงานใน Ruby / JS
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
คำถามนี้ถูกเพิ่มไปยังคำถามที่พบบ่อยของสแต็คโอเวอร์โฟลว์นิพจน์ปกติภายใต้ "Advanced Regex-Fu"
aliteralmind

คำตอบ:


21

การแสดงออกปกติ (ir) นี้ดูเหมือนว่าจะใช้ได้

^((?(1)((?(2)\2((?(3)\3((?(4)\4x{24}|x{60}))|x{50}))|x{15}))|x))*$

regex นี้เข้ากันได้กับรสชาติ PCRE, Perl, .NET

โดยทั่วไปแล้วจะตามด้วย "ต้นไม้ที่แตกต่าง" (ไม่แน่ใจว่ามีชื่อที่เหมาะสมหรือไม่) ซึ่งจะบอกให้ regex เห็นว่ามีอีกจำนวนเท่าใดที่ x ของการจับคู่สำหรับพลังงานที่สี่ต่อไป:

1     16    81    256   625   1296  2401 ...
   15    65    175   369   671   1105 ...
      50    110   194   302   434 ...
         60    84    108   132 ...
            24    24    24 ...  # the differences level out to 24 on the 4th iteration

\2, \3, \4ร้านค้าและการปรับปรุงความแตกต่างตามที่แสดงบน 2, 3 และแถวที่ 4 ตามลำดับ

โครงสร้างนี้สามารถขยายได้อย่างง่ายดายสำหรับพลังที่สูงขึ้น

ไม่แน่นอนเป็นทางออกที่สง่างาม แต่มันก็ใช้งานได้


+1 คำตอบที่ดี แม้ว่าคำตอบนี้จะแตกต่างจากของฉัน (ใช้ regex แบบมีเงื่อนไขในขณะที่ของฉันไม่ได้) แต่ก็มีวิญญาณเดียวกันกับโซลูชันของฉัน (ใช้ประโยชน์จากต้นไม้ที่แตกต่างกันและใช้ประโยชน์จากการอ้างอิงย้อนกลับของเครื่องยนต์ regex
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

ต้นไม้ที่แตกต่างความคิดที่เป็นระเบียบ สำหรับกำลังสองต้นไม้คือ 1 4 9 16 ... 3 5 7 ... 2 2 2 ใช่ไหม?
Sparr

@ Sparr ขอบคุณและใช่
ความผันผวน

24

ทางออกอื่น

นี่คือความคิดของฉันหนึ่งในปัญหาที่น่าสนใจที่สุดในเว็บไซต์ ฉันต้องขอบคุณdeadcodeสำหรับการชนมันกลับขึ้นไปด้านบน

^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$

39 ไบต์โดยไม่มีเงื่อนไขหรือยืนยัน ... เรียงลำดับจาก การสลับขณะใช้งาน ( ^|) เป็นประเภทของเงื่อนไขในการเลือกระหว่าง "การทำซ้ำครั้งแรก" และ "ไม่ใช่การทำซ้ำครั้งแรก"

regex นี้สามารถดูได้ที่นี่: http://regex101.com/r/qA5pK3/1

ทั้งสอง PCRE และ Python ตีความ regex ได้อย่างถูกต้องและก็ยังได้รับการทดสอบใน Perl ถึงn = 128รวมทั้งn 4 -1และn 4 +1


คำนิยาม

เทคนิคทั่วไปเหมือนกับในโซลูชันอื่น ๆ ที่โพสต์ไปแล้ว: กำหนดนิพจน์อ้างอิงตนเองซึ่งในแต่ละการวนซ้ำที่ตามมาตรงกับความยาวเท่ากับระยะถัดไปของฟังก์ชันความแตกต่างไปข้างหน้าD fโดยมีปริมาณไม่ จำกัด ( *) นิยามที่เป็นทางการของฟังก์ชันความแตกต่างไปข้างหน้า:

คำจำกัดความ 1: ฟังก์ชันความแตกต่างไปข้างหน้า

นอกจากนี้อาจมีการกำหนดฟังก์ชันความแตกต่างของคำสั่งซื้อที่สูงขึ้น:

คำจำกัดความ 2: ฟังก์ชั่นความแตกต่างเดินหน้าที่สอง

หรือโดยทั่วไปแล้ว:

คำจำกัดความที่ 3: ฟังก์ชันความแตกต่างไปข้างหน้า kth

ฟังก์ชันความแตกต่างไปข้างหน้ามีคุณสมบัติที่น่าสนใจมากมาย มันคือการจัดลำดับสิ่งที่อนุพันธ์เป็นฟังก์ชันต่อเนื่อง ยกตัวอย่างเช่นd fของพหุนามลำดับที่nจะเป็นพหุนามลำดับที่n-1เสมอและสำหรับiใด ๆ, ถ้าd f = i = d f + 1 i f , 1แล้วฟังก์ชันfคือเลขชี้กำลังในลักษณะเดียวกัน ว่าอนุพันธ์ของe xเท่ากับตัวของมันเอง ฟังก์ชั่นที่ไม่ต่อเนื่องที่ง่ายที่สุดที่ = D เป็น2 n


f (n) = n 2

ก่อนที่เราจะตรวจสอบวิธีการแก้ปัญหาข้างต้นเรามาเริ่มด้วยสิ่งที่ง่ายกว่ากันหน่อย: regex ที่จับคู่สตริงที่มีความยาวเป็นสี่เหลี่ยมจัตุรัสที่สมบูรณ์แบบ ตรวจสอบฟังก์ชันความแตกต่างไปข้างหน้า:

FDF: n ^ 2

ความหมายการทำซ้ำครั้งแรกควรตรงกับสตริงที่มีความยาว1สตริงที่สองที่มีความยาว3สตริงที่สามที่มีความยาว5เป็นต้นและโดยทั่วไปการทำซ้ำแต่ละครั้งควรจับคู่สตริงที่ยาวกว่าก่อนหน้านี้ regex ที่เกี่ยวข้องมีผลโดยตรงจากคำสั่งนี้:

^(^x|\1xx)*$

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

(1x$_)=~/^(^1|11\1)*$/

regex นี้สามารถวางนัยทั่วไปเพิ่มเติมเพื่อจับคู่ความยาวn-เหลี่ยมใด ๆ:

ตัวเลขสามเหลี่ยม:
^(^x|\1x{1})*$

หมายเลขสแควร์:
^(^x|\1x{2})*$

ตัวเลขห้าเหลี่ยม:
^(^x|\1x{3})*$

ตัวเลขหกเหลี่ยม:
^(^x|\1x{4})*$

เป็นต้น


f (n) = n 3

ไปที่n 3อีกครั้งตรวจสอบฟังก์ชันความแตกต่างไปข้างหน้า:

FDF: n ^ 3

อาจไม่ชัดเจนว่าจะใช้งานได้อย่างไรในทันทีดังนั้นเราจึงตรวจสอบฟังก์ชันความแตกต่างที่สองเช่นกัน:

FDF ^ 2: n ^ 3

ดังนั้นฟังก์ชันความแตกต่างของการส่งต่อจะไม่เพิ่มขึ้นตามค่าคงที่ แต่เป็นค่าเชิงเส้น เป็นเรื่องดีที่ค่าเริ่มต้น (' -1 th') ของD f 2เป็นศูนย์ซึ่งจะช่วยประหยัดการเริ่มต้นในการทำซ้ำครั้งที่สอง regex ที่ได้คือ:

^((^|\2x{6})(^x|\1))*$

การคำนวณซ้ำครั้งแรกจะจับคู่1เหมือนก่อนที่สองจะจับคู่สตริง6อีกต่อไป ( 7 ) ครั้งที่สามจะจับคู่สตริง12อีกต่อไป ( 19 ) เป็นต้น


f (n) = n 4

ฟังก์ชันความแตกต่างไปข้างหน้าสำหรับn 4 :

FDF: n ^ 4

ฟังก์ชั่นความแตกต่างไปข้างหน้าที่สอง:

FDF ^ 2: n ^ 4

ฟังก์ชั่นความแตกต่างไปข้างหน้าที่สาม:

FDF ^ 3: n ^ 4

ตอนนี้มันน่าเกลียด ค่าเริ่มต้นสำหรับD f 2และD f 3เป็นทั้งที่ไม่ใช่ศูนย์2และ12ตามลำดับซึ่งจะต้องมีการคิด ตอนนี้คุณคงทราบแล้วว่า regex จะเป็นไปตามรูปแบบนี้:

^((^|\2\3{b})(^|\3x{a})(^x|\1))*$

เพราะD 3จะต้องตรงกับความยาวของ12ทวนที่สองจำเป็นต้อง12 แต่เพราะมันจะเพิ่มจาก24ในแต่ละระยะที่ทำรังลึกต่อไปจะต้องใช้ค่าก่อนหน้านี้สองครั้งหมายความข = 2 สิ่งสุดท้ายที่จะทำคือการเริ่มต้นD 2 เนื่องจากD f 2มีอิทธิพลต่อD fโดยตรงซึ่งในที่สุดสิ่งที่เราต้องการจับคู่ค่าของมันจึงสามารถเริ่มต้นได้โดยการใส่อะตอมที่เหมาะสมลงใน regex โดยตรงในกรณีนี้ regex สุดท้ายจะกลายเป็น:(^|xx)

^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$

คำสั่งซื้อที่สูงขึ้น

พหุนามลำดับที่ห้าสามารถจับคู่กับ regex ต่อไปนี้:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$

f (n) = n 5คือการออกกำลังกายที่ค่อนข้างง่ายเนื่องจากค่าเริ่มต้นสำหรับทั้งสองฟังก์ชันที่แตกต่างกันไปข้างหน้าที่สองและที่สี่เป็นศูนย์:

^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$

สำหรับพหุนามลำดับที่หก:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$

สำหรับพหุนามลำดับที่เจ็ด:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$

เป็นต้น

โปรดทราบว่าไม่สามารถจับคู่ชื่อพหุนามทั้งหมดได้ด้วยวิธีนี้หากสัมประสิทธิ์ที่จำเป็นใด ๆ นั้นไม่ใช่จำนวนเต็ม ยกตัวอย่างเช่นn 6กำหนดให้A = 60 , B = 8และc = 3/2 สิ่งนี้สามารถแก้ไขได้ในกรณีนี้:

^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$

ที่นี่ฉันเปลี่ยนbเป็น6และcเป็น2ซึ่งมีผลิตภัณฑ์เหมือนกับค่าที่ระบุไว้ข้างต้น มันเป็นสิ่งสำคัญว่าสินค้านั้นไม่ได้เปลี่ยนเป็นใหม่··ขค· ...การควบคุมฟังก์ชั่นที่แตกต่างกันอย่างต่อเนื่องซึ่งสำหรับการสั่งซื้อที่หกพหุนามมีD 6 มีสองเริ่มต้นอะตอมปัจจุบัน: หนึ่งในการเริ่มต้นD ไป2เช่นเดียวกับn 4และอื่น ๆ ในการเริ่มต้นการทำงานที่แตกต่างกันห้า360ในขณะที่ในเวลาเดียวกันเพิ่มในหายไปสองคนจากข


คุณทดสอบเครื่องยนต์รุ่นใด
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

ในที่สุดฉันก็เข้าใจว่าเกิดอะไรขึ้น แน่นอนสิ่งเดียวที่จำเป็นคือการสนับสนุนสำหรับการอ้างอิงไปข้างหน้า +1
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@nhahtdh ahh คุณพูดถูก การอ้างอิงไปข้างหน้าไม่จำเป็นต้องเป็นคุณสมบัติสากลเช่นกัน
Primo

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

@ ลินน์ขอบคุณ! ไม่ได้คาดหวังว่า ...
โม่

13

นี่เป็นวิธีการแก้ปัญหาที่ไม่ได้ใช้การกำหนดเงื่อนไขการประกาศล่วงหน้าหรือการซ้อนทับย้อนหลัง Lookbehind กลุ่มการปรับสมดุลหรือการเรียกซ้ำ regex มันใช้ lookahead และการอ้างอิงย้อนกลับมาตรฐานซึ่งได้รับการสนับสนุนอย่างกว้างขวางมาก ฉันได้รับแรงบันดาลใจให้ทำงานภายใต้ข้อ จำกัด เหล่านี้เนื่องจากRegex Golfซึ่งใช้เอนจิ้น ECMAScript regex

วิธีการทำงานของ regex ขนาด 50 ไบต์นั้นค่อนข้างเรียบง่ายและแตกต่างจากโซลูชันอื่น ๆ ทั้งหมดที่ส่งไปยังตัวต่อปริศนานี้ มันน่าแปลกใจที่ค้นพบว่าตรรกะทางคณิตศาสตร์ชนิดนี้แสดงออกมาใน regex

      \2                     \4  \5
^((?=(xx+?)\2+$)((?=\2+$)(?=(x+)(\4+)$)\5){4})*x?$

(กลุ่มการจับภาพมีป้ายกำกับเหนือ regex)

regex สามารถทั่วไปจะมีอำนาจใด ๆ โดยเพียงแค่การเปลี่ยน4ใน{4}ที่มีอำนาจที่ต้องการ

ลองออนไลน์!

มันทำงานได้โดยการหารกำลังสี่ที่เล็กที่สุดของนายกที่ค่าปัจจุบันหารด้วย เชาวน์ปัญญาในแต่ละขั้นตอนจะเป็นกำลังสี่เสมอถ้าค่าเดิมเป็นกำลังสี่ ผลหารสุดท้ายของ 1 บ่งบอกว่าค่าดั้งเดิมนั้นเป็นกำลังสี่อย่างแน่นอน การแข่งขันจะเสร็จสิ้น ศูนย์ยังจับคู่

ก่อนอื่นจะใช้กลุ่มจับภาพขี้เกียจ\2เพื่อจับภาพตัวประกอบที่เล็กที่สุดของตัวเลขที่ใหญ่กว่า 1 ดังนั้นปัจจัยนี้จึงรับประกันได้ว่าจะเป็นนายก ตัวอย่างเช่นด้วย 1296 (6 ^ 4) จะเริ่มจับภาพ\2= 2

จากนั้นที่จุดเริ่มต้นของห่วงว่าจะถูกทำซ้ำครั้งที่ 4 นั้นจะทดสอบเพื่อดูว่าหมายเลขปัจจุบันคือโดยการหารด้วย\2 (?=\2+$)ครั้งแรกที่ผ่านลูปนี้การทดสอบนี้ไร้ประโยชน์ แต่จุดประสงค์ของมันจะชัดเจนในภายหลัง

ถัดจากภายในวงในนี้จะใช้กลุ่มการจับโลภ\4เพื่อจับภาพตัวประกอบที่ใหญ่ที่สุดของตัวเลขที่เล็กกว่าตัวมันเอง: (?=(x+)(\4+)$). ผลคือสิ่งนี้หารจำนวนด้วยปัจจัยหลักที่เล็กที่สุด, \2; ตัวอย่างเช่น 1296 จะถูกจับในขั้นต้นเป็น\4= 1296/2 = 648 โปรดทราบว่าการหารหมายเลขปัจจุบันโดย\2เป็นนัย ในขณะที่มันเป็นไปได้ที่จะแบ่งจำนวนปัจจุบันอย่างชัดเจนด้วยจำนวนที่มีอยู่ในกลุ่มการจับกุม (ซึ่งฉันค้นพบเพียงสี่วันหลังจากโพสต์คำตอบนี้) การทำเช่นนี้จะทำให้ regex ช้าลงและยากต่อการเข้าใจและไม่ใช่ จำเป็นเนื่องจากปัจจัยที่เล็กที่สุดของตัวเลขที่มากกว่า 1 จะตรงกับปัจจัยที่ใหญ่ที่สุดที่เล็กกว่าของตัวเองเสมอ (เช่นผลิตภัณฑ์ของพวกเขาเท่ากับจำนวนตัวเอง)

เนื่องจาก regex ชนิดนี้สามารถ "กินออกไป" จากสตริง (ทำให้เล็กลง) โดยปล่อยผลลัพธ์ไว้ที่จุดสิ้นสุดของสตริงเราจึงต้อง "ย้าย" ผลลัพธ์ของการหารไปยังจุดสิ้นสุดของสตริง นี้จะกระทำโดยการจับผลมาจากการลบ (ลบหมายเลขปัจจุบัน\4) ในกลุ่มจับ\5แล้วนอก lookahead \5จับคู่เป็นส่วนหนึ่งของการเริ่มต้นของหมายเลขปัจจุบันสอดคล้องกับที่ สิ่งนี้ทำให้สตริงที่ยังไม่ได้ประมวลผลที่เหลืออยู่ที่การจับคู่สิ้นสุด\4ในความยาว

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

ในตัวอย่างของเราด้วยอินพุต 1296 สิ่งนี้จะวนซ้ำดังนี้:

\2= 2
\4= 1296/2 = 648
\4= 648/2 = 324
\4= 324/2 = 162
\4= 162/2 = 81

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

\2= 3
\4= 81/3 = 27
\4= 27/3 = 9
\4= 9/3 = 3
\4= 3/3 = 1

ตอนนี้มันจะวนกลับไปที่ขั้นตอนแรกอีกครั้งโดยที่ 1 เป็นหมายเลขใหม่

หมายเลข 1 ไม่สามารถหารด้วยไพร์มใดก็ได้ซึ่งจะทำให้มันไม่ตรงตาม(?=(xx+?)\2+$)ดังนั้นจึงออกจากลูประดับบนสุด (อันที่มี*ในตอนท้าย) x?$ตอนนี้ก็มาถึง สิ่งนี้สามารถจับคู่กับศูนย์หรือหนึ่งเดียว หมายเลขปัจจุบัน ณ จุดนี้จะเป็น 0 หรือ 1 ถ้าหากหมายเลขเดิมเป็นกำลังสี่ที่สมบูรณ์แบบ ถ้าเป็น 0 ณ จุดนี้ก็หมายความว่าลูประดับบนสุดไม่เคยจับคู่อะไรเลยและถ้าเป็น 1 ก็หมายความว่าลูประดับบนสุดนั้นแบ่งกำลังสี่ระดับที่สมบูรณ์แบบลงจนกระทั่งมันไม่สามารถหารด้วยอะไรได้อีก (หรือ มันเป็น 1 ในสถานที่แรกหมายถึงห่วงระดับบนสุดไม่เคยจับคู่อะไรเลย)

นอกจากนี้ยังเป็นไปได้ที่จะแก้ปัญหานี้ใน 49 ไบต์ด้วยการแบ่งส่วนซ้ำอย่างชัดเจน (ซึ่งเป็นลักษณะทั่วไปสำหรับพลังทั้งหมด - แทนที่กำลังที่ต้องการลบหนึ่งลงใน{3}) แต่วิธีนี้ไกล, ช้ากว่าและคำอธิบายของอัลกอริธึมที่ใช้ เกินขอบเขตของคำตอบนี้:

^((x+)((\2(x+))(?=(\4*)\2*$)\4*(?=\5$\6)){3})?x?$

ลองออนไลน์!


จากการทดสอบของฉัน (ความยาวสูงสุด 1024) ดูเหมือนว่าถูกต้อง อย่างไรก็ตาม regex ช้าเกินไป - ใช้เวลานานมากในการจับคู่ความยาว 16 ^ 4 ดังนั้นจึงยากที่จะตรวจสอบจำนวนมาก แต่เนื่องจากไม่จำเป็นต้องมีประสิทธิภาพฉันจะอัปโหลดเมื่อฉันเข้าใจ regex ของคุณ
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
regex และความผันผวนของคุณยอดเยี่ยม ความเร็วและความกะทัดรัดของพวกเขาทำให้ฉันประหลาดใจทั้งคู่จับคู่ 100000000 ใน 7.5 วินาทีใน i7-2600k ของฉันเร็วกว่าที่ฉันคาดไว้ โซลูชันของฉันที่นี่มีขนาดแตกต่างกันโดยสิ้นเชิงเนื่องจากใช้เวลา 12 วินาทีในการจับคู่ 50625 แต่เป้าหมายของฉันไม่ใช่ความเร็ว แต่เป็นการทำงานให้สำเร็จด้วยความยาวรหัสน้อยที่สุดโดยใช้ชุดปฏิบัติการที่ จำกัด มากขึ้น
Deadcode

คำตอบของเรานั้นรวดเร็วเนื่องจากพวกเขาแทบจะไม่ย้อนรอย ((((x+)\5+)\4+)\3+)\2+$ขอทำมากของการย้อนรอยใน ของคุณก็น่าทึ่งในแบบของตัวเองเพราะฉันไม่สามารถแม้แต่จะคิดว่าจะจับคู่กับจำนวนสแควร์ได้อย่างไร
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

โดยวิธีการที่คำถามนี้ไม่ได้เป็นรหัสกอล์ฟ แต่เป็นปริศนา ฉันไม่ได้ตัดสินวิธีแก้ปัญหาด้วยความยาวรหัส
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

โอ้ (?:)ที่อธิบายว่าทำไมคุณใช้ ดังนั้นฉันควรแก้ไขคำตอบของฉันเพื่อให้เป็นรุ่นที่เหมาะสมที่สุดหรือไม่
Deadcode

8

วิธีการแก้

^(?:(?=(^|(?<=^x)x|xx\1))(?=(^|\1\2))(^x|\3\2{12}xx))*$

regex นี้เข้ากันได้กับรสชาติ Java, Perl, PCRE และ. NET regex นี้ใช้คุณสมบัติที่หลากหลาย: มองไปข้างหน้า, มองไปข้างหลังและอ้างอิงกลับไปข้างหน้าประกาศ ชนิดอ้างอิงย้อนกลับที่ได้รับการประกาศล่วงหน้าเป็นการจำกัดความเข้ากันได้ของ regex นี้กับเอ็นจินไม่กี่ตัว

คำอธิบาย

วิธีการแก้ปัญหานี้ทำให้การใช้งานที่ได้รับมาดังต่อไปนี้

โดยการขยายการรวมอย่างเต็มที่เราสามารถพิสูจน์ความเสมอภาคต่อไปนี้:

\ sum \ limit_ {i = 1} ^ n (i + 1) ^ 4 - \ sum \ limit_ {i = 1} ^ ni ^ 4 = (n + 1) ^ 4 - 1
\ sum \ limit_ {i = 1} ^ ni ^ 4 - \ sum \ limit_ {i = 1} ^ n (i-1) ^ 4 = n ^ 4

ให้เรารวมผลรวมที่ด้านซ้าย:

\ sum \ limit_ {i = 1} ^ n (4 (i + 1) ^ 3 - 6 (i + 1) ^ 2 + 4 (i + 1) - 1) = (n + 1) ^ 4 - 1
\ sum \ limit_ {i = 1} ^ n (4i ^ 3 - 6i ^ 2 + 4i - 1) = n ^ 4

ลบ 2 สมการ (สมการบนลบด้วยสมการด้านล่าง) แล้วรวมผลรวมทางด้านซ้ายมือแล้วทำให้มันง่ายขึ้น:

\ sum \ limit_ {i = 1} ^ n (12i ^ 2 + 2) = (n + 1) ^ 4 - n ^ 4 - 1

เราได้รับความแตกต่างระหว่างพลังที่สี่ต่อเนื่องกันเป็นกำลังรวม:

(n + 1) ^ 4 - n ^ 4 = \ sum \ limit_ {i = 1} ^ n (12i ^ 2 + 2) + 1

ซึ่งหมายความว่าความแตกต่างระหว่างพลังที่สี่ต่อเนื่องจะเพิ่มขึ้น (12n 2 + 2)

เพื่อให้ง่ายต่อการคิดอ้างถึงต้นไม้ที่แตกต่างในคำตอบของความผันผวน :

  • ทางด้านขวามือของสมการสุดท้ายคือแถวที่ 2 ในทรีแตกต่าง
  • การเพิ่มขึ้น (12n 2 + 2) คือแถวที่ 3 ในโครงสร้างต่างกัน

คณิตศาสตร์เพียงพอ กลับไปที่โซลูชันด้านบน:

  • กลุ่มการจับภาพที่ 1 รักษาชุดเลขคี่เพื่อคำนวณ i 2ดังที่เห็นในสมการ

    การพูดอย่างแม่นยำความยาวของกลุ่มการจับภาพที่ 1 จะเป็น 0 (ไม่ได้ใช้), 1, 3, 5, 7, ... ในขณะที่วนซ้ำ

    (?<=^x)xตั้งค่าเริ่มต้นสำหรับชุดเลขคี่ ^เป็นเพียงมีเพื่อให้มองไปข้างหน้าเพื่อความพึงพอใจในการย้ำแรก

    xx\1 เพิ่ม 2 และเลื่อนไปยังเลขคี่ถัดไป

  • กลุ่มจับ 2 รักษาชุดจำนวนตารางสำหรับฉัน2

    การพูดที่แม่นยำความยาวของกลุ่มการจับภาพที่ 2 จะเป็น 0, 1, 4, 9, ... ในขณะที่วนซ้ำ

    ^in (^|\1\2)ตั้งค่าเริ่มต้นสำหรับชุดหมายเลขตาราง และ\1\2เพิ่มเลขคี่ไปยังหมายเลขสแควร์ปัจจุบันเพื่อเลื่อนไปยังหมายเลขสแควร์ถัดไป

  • กลุ่มการจับภาพที่ 3 (นอกการมองไปข้างหน้าและการใช้ข้อความจริง) ตรงกับด้านขวาทั้งหมดของสมการที่เราได้รับด้านบน

    ^xใน(^x|\3\2{12}xx)ชุดค่าเริ่มต้นซึ่งเป็น+ 1ด้านขวามือของสมการ

    \3\2{12}xxเพิ่มความแตกต่างที่เพิ่มขึ้น (12n 2 + 2) โดยใช้ n 2จากการจับภาพกลุ่ม 2 และจับคู่ความแตกต่างในเวลาเดียวกัน

ข้อตกลงนี้เป็นไปได้เนื่องจากจำนวนของข้อความที่ตรงในแต่ละซ้ำมากกว่าหรือเท่ากับจำนวนของข้อความที่จำเป็นในการดำเนินการมองไปข้างหน้าเพื่อสร้าง n 2

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