Võng mạc , 66 63 45 43 36 byte
^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$
Mặc dù tiêu đề nói Retina, đây chỉ là một regex .NET đơn giản chấp nhận các đại diện đơn nhất của các số Loeschian.
Đầu vào 999 và 1000 hoạt động tốt trong một giây.
Hãy thử trực tuyến! (Dòng đầu tiên cho phép bộ thử nghiệm được phân tách bằng nguồn cấp dữ liệu và hai dòng tiếp theo đảm nhiệm việc chuyển đổi thành đơn nguyên để thuận tiện.)
Giải trình
Giải pháp dựa trên phân loại rằng đầu vào có thể được viết là i*i + j*(i + j)
dương i
và không âm j
(vì chúng ta không phải xử lý đầu vào 0
) và đó n*n
chỉ là tổng của các n
số nguyên lẻ đầu tiên . Chơi golf này là một bài tập thú vị trong các tài liệu tham khảo về phía trước.
Một "tham chiếu chuyển tiếp" là khi bạn đặt một phản hồi trong nhóm mà nó đề cập đến. Tất nhiên điều đó không hoạt động khi nhóm được sử dụng lần đầu tiên, vì chưa có gì để phản hồi, nhưng nếu bạn đặt điều này trong một vòng lặp, thì phản hồi sẽ được ghi lại lần lặp trước đó mỗi lần. Đến lượt mình, chúng ta hãy xây dựng một bản chụp lớn hơn với mỗi lần lặp. Điều này có thể được sử dụng để tạo các mẫu rất nhỏ gọn cho những thứ như số tam giác, hình vuông và số Fibonacci.
Ví dụ, sử dụng thực tế là các hình vuông chỉ là tổng của các n
số nguyên lẻ đầu tiên , chúng ta có thể khớp với một đầu vào hình vuông như thế này:
(^.|..\1)+$
Ở lần lặp đầu tiên, ..\1
không thể làm việc, vì \1
chưa có giá trị. Vì vậy, chúng tôi bắt đầu với ^.
, bắt một nhân vật duy nhất vào nhóm 1
. Ở các lần lặp lại tiếp theo, ^.
không còn phù hợp do neo, nhưng bây giờ ..\1
là hợp lệ. Nó khớp với hai ký tự nhiều hơn lần lặp trước và cập nhật bản chụp. Bằng cách này, chúng ta khớp các số lẻ tăng dần, nhận được một hình vuông sau mỗi lần lặp.
Thật không may, chúng ta không thể sử dụng kỹ thuật này. Sau khi kết hợp i*i
, chúng ta cũng cần phải có được i
, để chúng ta có thể nhân nó với j
. Một cách đơn giản (nhưng dài) để làm điều này là sử dụng thực tế là việc khớp i*i
sẽ i
lặp đi lặp lại, để chúng tôi nắm bắt được i
mọi thứ trong nhóm 1
. Bây giờ chúng ta có thể sử dụng các nhóm cân bằng để giải nén điều này i
, nhưng như tôi đã nói là tốn kém.
Thay vào đó, tôi đã tìm ra một cách khác để viết "tổng các số nguyên lẻ liên tiếp" này cũng mang lại i
một nhóm bắt giữ ở cuối. Tất nhiên i
số lẻ thứ chỉ là 2i-1
. Điều này cho chúng ta một cách để tăng tham chiếu chuyển tiếp chỉ bằng 1 trên mỗi lần lặp. Đó là phần này:
^()(\1(?<1>.\1))+
Đây ()
chỉ đẩy một chụp rỗng vào nhóm 1
(initialising i
đến 0
). Điều này khá giống với ^.|
giải pháp đơn giản ở trên, nhưng sử dụng |
trong trường hợp này sẽ khó khăn hơn một chút.
Sau đó, chúng ta có vòng lặp chính (\1(?<1>.\1))
. \1
phù hợp với trước đó i
, (?<1>.\1)
sau đó cập nhật nhóm 1
với i+1
. Về mặt mới i
, chúng tôi chỉ phù hợp với các 2i-1
nhân vật. Chính xác những gì chúng ta cần.
Khi chúng tôi hoàn thành, chúng tôi đã khớp một số hình vuông i*i
và nhóm 1
vẫn giữ các i
ký tự.
Phần thứ hai gần hơn với kết hợp hình vuông đơn giản mà tôi đã trình bày ở trên. Bây giờ chúng ta hãy bỏ qua phản 1
ứng ngược:
(.(?(4).\1))*
Điều này về cơ bản giống như (^.|..\4)*
, ngoại trừ việc chúng ta không thể sử dụng ^
vì chúng ta không ở đầu chuỗi. Thay vào đó, chúng tôi sử dụng một điều kiện, để chỉ khớp với bổ sung .\1
khi chúng tôi đã sử dụng nhóm 4
. Nhưng trong thực tế, điều này là hoàn toàn giống nhau. Điều này cho chúng ta j*j
.
Điều duy nhất còn thiếu là j*i
thuật ngữ. Chúng tôi kết hợp điều này với j*j
bằng cách sử dụng thực tế là việc j*j
tính toán vẫn có các j
bước lặp. Vì vậy, cho mỗi lần lặp chúng tôi cũng tiến con trỏ bằng i
với \1
. Chúng ta chỉ cần đảm bảo không viết nó thành nhóm 4
, vì điều đó sẽ gây rối với việc khớp các số lẻ liên tiếp. Đó là cách chúng tôi đến:
(\1(.(?(4).\1)))*