Regex (ECMAScript), 85 73 71 byte
^((?=(x*?)\2(\2{4})+$|(x*?)(\4\4xx)*$)(\2\4|(x*)\5\7\7(?=\4\7$\2)\B))*$
Hãy thử trực tuyến!
giải thích bởi Deadcode
Phiên bản 73 byte trước đó được giải thích bên dưới.
^((?=(x*?)\2(\2{4})+$)\2|(?=(x*?)(\4\4xx)*$)(\4|\5(x*)\7\7(?=\4\7$)\B))+$
Do những hạn chế của biểu thức chính của ECMAScript, một chiến thuật hiệu quả thường là biến đổi bước số một tại một thời điểm trong khi vẫn giữ bất động sản cần thiết ở mọi bước. Ví dụ, để kiểm tra một hình vuông hoàn hảo hoặc công suất là 2, hãy giảm số lượng kích thước trong khi vẫn giữ cho hình vuông hoặc công suất là 2 (tương ứng) ở mỗi bước.
Đây là những gì giải pháp này làm ở mỗi bước:
1
1
1
10
01
01
o n e s > ze r o e s1
o n e s > ze r o e s ⇔ o n e s - 1 > ze r o e s - 1
Khi các bước lặp lại này không thể tiến xa hơn, kết quả cuối cùng sẽ là một chuỗi 1
bit liền kề , rất nặng và chỉ ra rằng số ban đầu cũng nặng, hoặc lũy thừa bằng 2, cho thấy số ban đầu không nặng.
Và tất nhiên, mặc dù các bước này được mô tả ở trên về mặt thao tác chính tả trên biểu diễn nhị phân của số, chúng thực sự được thực hiện dưới dạng số học đơn phương.
# 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.