Saya memikirkan pendekatan membagi dan menaklukkan yang mungkin berhasil.
Pertama, dalam preprocessing Anda harus memasukkan semua angka kurang dari setengah ukuran input Anda ( n / 3) ke dalam daftar.
Diberikan string: 0000010101000100
(perhatikan bahwa contoh khusus ini valid)
Masukkan semua bilangan prima (dan 1) dari 1 hingga (16/2) ke dalam daftar: {1, 2, 3, 4, 5, 6, 7}
Kemudian bagi menjadi dua:
100000101 01000100
Terus lakukan ini sampai Anda mendapatkan string ukuran 1. Untuk semua string ukuran-satu dengan 1 di dalamnya, tambahkan indeks string ke daftar kemungkinan; jika tidak, kembalikan -1 untuk kegagalan.
Anda juga harus mengembalikan daftar jarak spasi yang masih mungkin, terkait dengan setiap indeks awal. (Mulailah dengan daftar yang Anda buat di atas dan hapus angka saat Anda pergi) Di sini, daftar kosong berarti Anda hanya berurusan dengan satu 1 dan sehingga spasi apa pun mungkin pada saat ini; kalau tidak, daftar mencakup jarak yang harus dikesampingkan.
Jadi lanjutkan dengan contoh di atas:
1000 0101 0100 0100
10 00 01 01 01 00 01 00
1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0
Pada langkah menggabungkan pertama, kami memiliki delapan set dua sekarang. Pada yang pertama, kita memiliki kemungkinan satu set, tetapi kita belajar bahwa spasi dengan 1 tidak mungkin karena nol lainnya ada di sana. Jadi kita mengembalikan 0 (untuk indeks) dan {2,3,4,5,7} untuk fakta bahwa spasi dengan 1 tidak mungkin. Yang kedua, kita tidak punya apa-apa dan jadi -1. Yang ketiga kami memiliki kecocokan tanpa spasi dihilangkan dalam indeks 5, jadi kembalikan 5, {1,2,3,4,5,7}. Pada pasangan keempat kita kembalikan 7, {1,2,3,4,5,7}. Di urutan kelima, kembalikan 9, {1,2,3,4,5,7}. Di keenam, kembali -1. Di ketujuh, kembalikan 13, {1,2,3,4,5,7}. Di kedelapan, kembalikan -1.
Menggabungkan lagi menjadi empat set empat, kami memiliki:
1000
: Return (0, {4,5,6,7})
0101
: Return (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: Kembali (9, {3,4,5,6,7})
0100
: Kembali (13, {3,4,5,6,7})
Menggabungkan ke dalam set delapan:
10000101
: Return (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Return (9, {4,7}), (13, {3,4,5,6,7})
Menggabungkan ke dalam satu set enam belas:
10000101 01000100
Seiring kemajuan kami, kami terus memeriksa semua kemungkinan sejauh ini. Hingga langkah ini kami telah meninggalkan hal-hal yang melampaui akhir dari string, tetapi sekarang kami dapat memeriksa semua kemungkinan.
Pada dasarnya, kami memeriksa 1 pertama dengan jarak 5 dan 7, dan menemukan bahwa mereka tidak berbaris ke 1. (Perhatikan bahwa setiap cek adalah KONSTAN, bukan waktu linier) Kemudian kita periksa yang kedua (indeks 5) dengan jarak 2, 3, 4, 5, 6, dan 7-- atau kita mau, tetapi kita bisa berhenti pada 2 karena yang benar-benar cocok.
Fiuh! Itu algoritma yang agak panjang.
Saya tidak tahu 100% apakah itu O (n log n) karena langkah terakhir, tetapi semua yang ada pasti O (n log n) sejauh yang saya tahu. Saya akan kembali ke sini nanti dan mencoba untuk memperbaiki langkah terakhir.
EDIT: Mengubah jawaban saya untuk mencerminkan komentar Welbog. Maaf atas kesalahannya. Saya akan menulis beberapa pseudocode nanti, ketika saya mendapat lebih banyak waktu untuk menguraikan apa yang saya tulis lagi. ;-)