Solusi Lain
Menurut saya ini adalah salah satu masalah paling menarik di situs ini. Saya perlu berterima kasih pada deadcode karena menabraknya kembali ke atas.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 byte , tanpa persyaratan atau pernyataan ... semacam. Alternatifnya, seperti yang sedang digunakan ( ^|
), adalah jenis kondisional dalam suatu cara, untuk memilih antara "iterasi pertama," dan "bukan iterasi pertama."
Regex ini dapat dilihat berfungsi di sini: http://regex101.com/r/qA5pK3/1
Baik PCRE dan Python menginterpretasikan regex dengan benar, dan itu juga telah diuji dalam Perl hingga n = 128 , termasuk n 4 -1 , dan n 4 +1 .
Definisi
Teknik umum adalah sama seperti pada solusi lain sudah diposting: menentukan ekspresi diri-referensi yang pada setiap iterasi berikutnya sesuai panjang yang sama dengan istilah berikutnya fungsi perbedaan maju, D f , dengan quantifier terbatas ( *
). Definisi formal fungsi perbedaan maju:
Selain itu, fungsi perbedaan urutan yang lebih tinggi juga dapat didefinisikan:
Atau, lebih umum:
Fungsi perbedaan maju memiliki banyak sifat menarik; itu adalah urutan apa turunannya untuk fungsi kontinu. Misalnya, D f dari n th rangka polinomial akan selalu menjadi n-1 th rangka polinomial, dan untuk setiap i , jika D f i = D f i + 1 , maka fungsi f adalah eksponensial, dalam banyak cara yang sama bahwa turunan dari e x sama dengan dirinya sendiri. Fungsi diskrit paling sederhana di mana f = D f adalah 2 n .
f (n) = n 2
Sebelum kita memeriksa solusi di atas, mari kita mulai dengan sesuatu yang sedikit lebih mudah: regex yang cocok dengan string yang panjangnya adalah kuadrat sempurna. Meneliti fungsi perbedaan maju:
Artinya, iterasi pertama harus cocok dengan string dengan panjang 1 , yang kedua string dengan panjang 3 , yang ketiga string dengan panjang 5 , dll., Dan secara umum, setiap iterasi harus cocok dengan string yang dua lebih panjang dari sebelumnya. Regex yang sesuai mengikuti hampir secara langsung dari pernyataan ini:
^(^x|\1xx)*$
Dapat dilihat bahwa iterasi pertama hanya akan cocok dengan satu x
, dan setiap iterasi berikutnya akan cocok dengan string dua lebih lama dari sebelumnya, persis seperti yang ditentukan. Ini juga menyiratkan tes kuadrat sempurna pendek luar biasa di perl:
(1x$_)=~/^(^1|11\1)*$/
Regex ini dapat digeneralisasikan lebih lanjut untuk mencocokkan dengan panjang n- gonal:
Angka segitiga:
^(^x|\1x{1})*$
Angka kuadrat:
^(^x|\1x{2})*$
Angka pentagonal:
^(^x|\1x{3})*$
Angka heksagonal:
^(^x|\1x{4})*$
dll.
f (n) = n 3
Pindah ke n 3 , sekali lagi memeriksa fungsi perbedaan maju:
Mungkin tidak segera jelas cara mengimplementasikan ini, jadi kami memeriksa fungsi perbedaan kedua juga:
Jadi, fungsi perbedaan ke depan tidak meningkat dengan nilai konstan, melainkan nilai linier. Itu bagus bahwa ( 'awal -1 th') nilai D f 2 adalah nol, yang menyimpan sebuah inisialisasi pada iterasi kedua. Regex yang dihasilkan adalah sebagai berikut:
^((^|\2x{6})(^x|\1))*$
Iterasi pertama akan cocok dengan 1 , seperti sebelumnya, yang kedua akan cocok dengan string 6 lebih panjang ( 7 ), yang ketiga akan cocok dengan string 12 lebih lama ( 19 ), dll.
f (n) = n 4
Fungsi perbedaan maju untuk n 4 :
Fungsi perbedaan maju kedua:
Fungsi perbedaan maju ketiga:
Nah, itu jelek. Nilai awal untuk D f 2 dan D f 3 keduanya bukan nol, 2 dan 12 masing-masing, yang perlu dipertanggungjawabkan. Anda mungkin sudah tahu sekarang bahwa regex akan mengikuti pola ini:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Karena D f 3 harus sesuai panjang 12 pada iterasi kedua, sebuah niscaya 12 . Tetapi karena ia bertambah 24 setiap istilah, sarang yang lebih dalam berikutnya harus menggunakan nilai sebelumnya dua kali, menyiratkan b = 2 . Hal terakhir yang perlu dilakukan adalah menginisialisasi D f 2 . Karena D f 2 pengaruh D f langsung, yang pada akhirnya apa yang kita ingin mencocokkan, nilainya dapat diinisialisasi dengan menyisipkan atom yang tepat langsung ke regex, dalam hal ini (^|xx)
. Regex terakhir kemudian menjadi:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Pesanan Tinggi
Polinomial urutan kelima dapat dicocokkan dengan regex berikut:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 adalah latihan yang cukup mudah, karena nilai awal untuk fungsi perbedaan maju kedua dan keempat adalah nol:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Untuk enam polinomial pesanan:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Untuk polinomial urutan ketujuh:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
dll.
Perhatikan bahwa tidak semua polinomial dapat dicocokkan dengan cara ini, jika salah satu koefisien yang diperlukan adalah non-integer. Sebagai contoh, n 6 mensyaratkan bahwa a = 60 , b = 8 , dan c = 3/2 . Ini dapat diatasi, dalam hal ini:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Di sini saya telah mengubah b menjadi 6 , dan c menjadi 2 , yang memiliki produk yang sama dengan nilai yang dinyatakan di atas. Sangat penting bahwa produk tidak berubah, karena a · b · c · ... mengontrol fungsi perbedaan konstan, yang untuk polinomial urutan keenam adalah D f 6 . Ada dua atom inisialisasi hadir: satu untuk menginisialisasi D f ke 2 , seperti dengan n 4 , dan yang lainnya untuk menginisialisasi fungsi perbedaan kelima menjadi 360 , sementara pada saat yang sama menambahkan dua yang hilang dari b .