Regex (ECMAScript), 85 73 71 ไบต์
^((?=(x*?)\2(\2{4})+$|(x*?)(\4\4xx)*$)(\2\4|(x*)\5\7\7(?=\4\7$\2)\B))*$
ลองออนไลน์!
คำอธิบายโดยDeadcode
เวอร์ชั่น 73 ไบต์ก่อนหน้านี้อธิบายไว้ด้านล่าง
^((?=(x*?)\2(\2{4})+$)\2|(?=(x*?)(\4\4xx)*$)(\4|\5(x*)\7\7(?=\4\7$)\B))+$
เนื่องจากข้อ จำกัด ของ ECMAScript regex ชั้นเชิงที่มีประสิทธิภาพมักจะเปลี่ยนหมายเลขหนึ่งครั้งในขณะที่รักษาค่าคงที่ของคุณสมบัติที่จำเป็นในทุกขั้นตอน ตัวอย่างเช่นในการทดสอบกำลังสองที่สมบูรณ์แบบหรือกำลังสองให้ลดจำนวนลงในขณะที่รักษากำลังสองหรือกำลังสอง (ตามลำดับ) ทุกขั้นตอน
นี่คือสิ่งที่โซลูชันนี้ทำในทุกขั้นตอน:
1
1
1
10
01
01
ones>zeroes1
ones>zeroes⇔ones−1>zeroes−1
เมื่อขั้นตอนที่ทำซ้ำเหล่านี้ไม่สามารถไปได้อีกต่อไปผลลัพธ์สุดท้ายจะเป็นสตริงของ1
บิตที่ต่อเนื่องกันซึ่งมีน้ำหนักมากและบ่งชี้ว่าหมายเลขเดิมนั้นหนักเกินไปหรือกำลัง 2 แสดงว่าหมายเลขเดิมไม่หนัก
และแน่นอนถึงแม้ว่าขั้นตอนเหล่านี้จะอธิบายไว้ข้างต้นในแง่ของการจัดการเกี่ยวกับการพิมพ์บนเลขฐานสองของตัวเลข
# For these comments, N = the number to the right of the "cursor", a.k.a. "tail",
# and "rightmost" refers to the big-endian binary representation of N.
^
( # if N is even and not a power of 2:
(?=(x*?)\2(\2{4})+$) # \2 = smallest divisor of N/2 such that the quotient is
# odd and greater than 1; as such, it is guaranteed to be
# the largest power of 2 that divides N/2, iff N is not
# itself a power of 2 (using "+" instead of "*" is what
# prevents a match if N is a power of 2).
\2 # N = N - \2. This changes the rightmost "10" to a "01".
| # else (N is odd or a power of 2)
(?=(x*?)(\4\4xx)*$) # \4+1 = smallest divisor of N+1 such that the quotient is
# odd; as such, \4+1 is guaranteed to be the largest power
# of 2 that divides N+1. So, iff N is even, \4 will be 0.
# Another way of saying this: \4 = the string of
# contiguous 1 bits from the rightmost part of N.
# \5 = (\4+1) * 2 iff N+1 is not a power of 2, else
# \5 = unset (NPCG) (iff N+1 is a power of 2), but since
# N==\4 iff this is the case, the loop will exit
# immediately anyway, so an unset \5 will never be used.
(
\4 # N = N - \4. If N==\4 before this, it was all 1 bits and
# therefore heavy, so the loop will exit and match. This
# would work as "\4$", and leaving out the "$" is a golf
# optimization. It still works without the "$" because if
# N is no longer heavy after having \4 subtracted from it,
# this will eventually result in a non-match which will
# then backtrack to a point where N was still heavy, at
# which point the following alternative will be tried.
|
# N = (N + \4 - 2) / 4. This removes the rightmost "01". As such, it removes
# an equal number of 0 bits and 1 bits (one of each) and the heaviness of N
# is invariant before and after. This fails to match if N is a power of 2,
# and in fact causes the loop to reach a dead end in that case.
\5 # N = N - (\4+1)*2
(x*)\7\7(?=\4\7$) # N = (N - \4) / 4 + \4
\B # Assert N > 0 (this would be the same as asserting N > 2
# before the above N = (N + \4 - 2) / 4 operation).
)
)+
$ # This can only be a match if the loop was exited due to N==\4.