Saya ingin menulis fungsi yang mengambil array huruf sebagai argumen dan sejumlah huruf untuk memilih.
Katakanlah Anda memberikan array 8 huruf dan ingin memilih 3 huruf dari itu. Maka Anda harus mendapatkan:
8! / ((8 - 3)! * 3!) = 56
Array (atau kata-kata) sebagai imbalannya masing-masing terdiri dari 3 huruf.
algorithm
combinations
ique
sumber
sumber
Jawaban:
Seni Pemrograman Komputer Volume 4: Fascicle 3 memiliki banyak ini yang mungkin cocok dengan situasi khusus Anda lebih baik daripada cara saya menggambarkan.
Kode Abu-abu
Masalah yang akan Anda temui tentu saja adalah memori dan cukup cepat, Anda akan memiliki masalah dengan 20 elemen di set Anda - 20 C 3 = 1140. Dan jika Anda ingin beralih di set, yang terbaik adalah menggunakan abu-abu yang dimodifikasi algoritma kode sehingga Anda tidak menyimpan semuanya dalam memori. Ini menghasilkan kombinasi berikutnya dari sebelumnya dan menghindari pengulangan. Ada banyak dari ini untuk kegunaan yang berbeda. Apakah kita ingin memaksimalkan perbedaan antara kombinasi yang berurutan? memperkecil? dan lain-lain.
Beberapa makalah asli yang menggambarkan kode abu-abu:
Berikut adalah beberapa makalah lain yang membahas topik ini:
Chase's Twiddle (algoritme)
Phillip J Chase, ` Algoritma 382: Kombinasi M out of N Objects '(1970)
Algoritme dalam C ...
Indeks Kombinasi dalam Urutan Leksikografis (Algoritma Buckles 515)
Anda juga dapat mereferensikan kombinasi berdasarkan indeksnya (dalam urutan leksikografis). Menyadari bahwa indeks harus berupa sejumlah perubahan dari kanan ke kiri berdasarkan indeks, kita dapat membuat sesuatu yang harus memulihkan kombinasi.
Jadi, kami memiliki satu set {1,2,3,4,5,6} ... dan kami ingin tiga elemen. Katakanlah {1,2,3} kita dapat mengatakan bahwa perbedaan antara elemen adalah satu dan dalam urutan dan minimal. {1,2,4} memiliki satu perubahan dan secara leksikografis nomor 2. Jadi jumlah 'perubahan' di tempat terakhir menyumbang satu perubahan dalam pemesanan leksikografis. Tempat kedua, dengan satu perubahan {1,3,4} memiliki satu perubahan tetapi menyumbang lebih banyak perubahan karena berada di tempat kedua (sebanding dengan jumlah elemen dalam set asli).
Metode yang saya jelaskan adalah dekonstruksi, seperti yang terlihat, dari set ke indeks, kita perlu melakukan sebaliknya - yang jauh lebih rumit. Inilah cara Buckles memecahkan masalah. Saya menulis beberapa C untuk menghitungnya , dengan perubahan kecil - Saya menggunakan indeks set daripada rentang angka untuk mewakili set, jadi kami selalu bekerja dari 0 ... n. catatan:
Indeks Kombinasi dalam Urutan Leksikografis (McCaffrey)
Ada cara lain : konsepnya lebih mudah dipahami dan diprogram tetapi tanpa optimalisasi Buckles. Untungnya, itu juga tidak menghasilkan kombinasi duplikat:
Himpunan yang memaksimalkan , di mana .
Untuk contoh:
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Jadi, kombinasi leksikografis ke-27 dari empat hal adalah: {1,2,5,6}, itu adalah indeks dari set apa pun yang ingin Anda lihat. Contoh di bawah ini (OCaml), memerlukanchoose
fungsi, diserahkan kepada pembaca:Iterator kombinasi kecil dan sederhana
Dua algoritma berikut disediakan untuk tujuan didaktik. Mereka menerapkan iterator dan (secara keseluruhan) folder kombinasi keseluruhan. Mereka adalah secepat mungkin, memiliki kompleksitas O ( n C k ). Konsumsi memori terikat oleh
k
.Kami akan mulai dengan iterator, yang akan memanggil fungsi yang disediakan pengguna untuk setiap kombinasi
Versi yang lebih umum akan memanggil fungsi yang disediakan pengguna bersama dengan variabel status, mulai dari status awal. Karena kita harus melewati status di antara berbagai status, kita tidak akan menggunakan for-loop, tetapi sebaliknya, gunakan rekursi,
sumber
Dalam C #:
Pemakaian:
Hasil:
sumber
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Solusi java pendek:
Hasilnya akan
sumber
Bolehkah saya menyajikan solusi Python rekursif saya untuk masalah ini?
Contoh penggunaan:
Saya suka karena kesederhanaannya.
sumber
len(tuple(itertools.combinations('abcdefgh',3)))
akan mencapai hal yang sama di Python dengan kode lebih sedikit.for i in xrange(len(elements) - length + 1):
? Tidak masalah dalam python karena akan keluar dari indeks slice ditangani dengan anggun tetapi itu adalah algoritma yang benar.Katakanlah susunan huruf Anda terlihat seperti ini: "ABCDEFGH". Anda memiliki tiga indeks (i, j, k) yang menunjukkan huruf mana yang akan Anda gunakan untuk kata saat ini, Anda mulai dengan:
Pertama Anda bervariasi k, sehingga langkah selanjutnya terlihat seperti itu:
Jika Anda mencapai akhir, Anda melanjutkan dan memvariasikan j lalu k lagi.
Begitu Anda mencapai G, Anda juga mulai memvariasikan i.
Ditulis dalam kode ini terlihat seperti itu
sumber
Algoritma rekursif berikut mengambil semua kombinasi elemen-k dari set yang dipesan:
i
kombinasi Andai
dengan masing-masing kombinasik-1
elemen yang dipilih secara rekursif dari set elemen yang lebih besar darii
.Iterasi di atas untuk masing-masing
i
di set.Sangat penting bagi Anda untuk memilih sisa elemen yang lebih besar daripada
i
, untuk menghindari pengulangan. Dengan cara ini [3,5] akan dipilih hanya sekali, karena [3] dikombinasikan dengan [5], bukan dua kali (kondisi ini menghilangkan [5] + [3]). Tanpa kondisi ini Anda mendapatkan variasi, bukan kombinasi.sumber
Dalam C ++ rutin berikut akan menghasilkan semua kombinasi jarak panjang (pertama, k) antara rentang [pertama, terakhir):
Dapat digunakan seperti ini:
Ini akan mencetak yang berikut ini:
sumber
being
danbegin
dengans.begin()
, danend
dengans.end()
. Kode erat mengikutinext_permutation
algoritma STL , dijelaskan di sini lebih terinci.Saya menemukan utas ini bermanfaat dan saya pikir saya akan menambahkan solusi Javascript yang bisa Anda masukkan ke Firebug. Tergantung pada mesin JS Anda, mungkin butuh sedikit waktu jika string awal besar.
Outputnya harus sebagai berikut:
sumber
sumber
Contoh singkat dengan Python:
Untuk penjelasan, metode rekursif dijelaskan dengan contoh berikut:
Contoh: ABCDE
Semua kombinasi 3 adalah:
sumber
Algoritma rekursif sederhana di Haskell
Kami pertama-tama mendefinisikan kasus khusus, yaitu memilih elemen nol. Ini menghasilkan hasil tunggal, yang merupakan daftar kosong (yaitu daftar yang berisi daftar kosong).
Untuk n> 0,
x
telusuri setiap elemen daftar danxs
setiap elemen setelahnyax
.rest
mengambiln - 1
elemen darixs
menggunakan panggilan rekursif kecombinations
. Hasil akhir dari fungsi adalah daftar di mana setiap elemenx : rest
(yaitu daftar yang memilikix
kepala danrest
ekor) untuk setiap nilai berbeda darix
danrest
.Dan tentu saja, karena Haskell malas, daftar ini secara bertahap dihasilkan sesuai kebutuhan, sehingga Anda dapat mengevaluasi sebagian kombinasi besar secara eksponensial.
sumber
Dan inilah kakek COBOL, bahasa yang banyak difitnah.
Mari kita asumsikan sebuah array yang terdiri dari 34 elemen masing-masing 8 byte (murni seleksi arbitrer). Idenya adalah untuk menghitung semua kemungkinan kombinasi 4-elemen dan memuatnya ke dalam sebuah array.
Kami menggunakan 4 indeks, masing-masing satu untuk setiap posisi dalam grup 4
Array diproses seperti ini:
Kami memvariasikan idx4 dari 4 hingga akhir. Untuk setiap idx4 kami mendapatkan kombinasi unik dari kelompok empat. Ketika idx4 sampai di akhir array, kami menambah idx3 dengan 1 dan mengatur idx4 ke idx3 + 1. Kemudian kita jalankan idx4 sampai akhir lagi. Kami melanjutkan dengan cara ini, menambah masing-masing idx3, idx2, dan idx1 sampai posisi idx1 kurang dari 4 dari akhir array. Itu menyelesaikan algoritme.
Iterasi pertama:
Contoh COBOL:
sumber
Berikut ini adalah implementasi generik yang elegan di Scala, seperti dijelaskan pada 99 Masalah Scala .
sumber
Jika Anda dapat menggunakan sintaks SQL - katakanlah, jika Anda menggunakan LINQ untuk mengakses bidang struktur atau array, atau langsung mengakses database yang memiliki tabel yang disebut "Alfabet" dengan hanya satu bidang char "Surat", Anda dapat beradaptasi mengikuti kode:
Ini akan mengembalikan semua kombinasi dari 3 huruf, terlepas dari berapa banyak huruf yang Anda miliki dalam tabel "Alfabet" (bisa 3, 8, 10, 27, dll.).
Jika yang Anda inginkan adalah semua permutasi, bukan kombinasi (yaitu Anda ingin "ACB" dan "ABC" dihitung sebagai berbeda, daripada muncul sekali saja) hapus saja baris terakhir (DAN DAN satu) dan selesai.
Post-Edit: Setelah membaca kembali pertanyaan, saya menyadari apa yang dibutuhkan adalah algoritma umum , bukan hanya yang spesifik untuk kasus memilih 3 item. Jawaban Adam Hughes adalah jawaban yang lengkap, sayangnya saya belum bisa memberikan suaranya. Jawaban ini sederhana tetapi hanya berfungsi bila Anda menginginkan 3 item.
sumber
Versi C # lainnya dengan generasi malas dari indeks kombinasi. Versi ini mempertahankan satu larik indeks untuk menentukan pemetaan antara daftar semua nilai dan nilai untuk kombinasi saat ini, yaitu terus-menerus menggunakan ruang tambahan O (k) selama seluruh runtime. Kode menghasilkan kombinasi individual, termasuk yang pertama, di O (k) .
Kode uji:
Keluaran:
sumber
c b a
yang tidak.https://gist.github.com/3118596
Ada implementasi untuk JavaScript. Ini memiliki fungsi untuk mendapatkan k-kombinasi dan semua kombinasi dari array objek apa pun. Contoh:
sumber
Di sini Anda memiliki versi malas yang dievaluasi dari algoritma yang dikodekan dalam C #:
Dan bagian uji:
Semoga ini bisa membantu Anda!
sumber
Saya memiliki algoritma permutasi yang saya gunakan untuk project euler, dengan python:
Jika
Anda harus memiliki semua kombinasi yang Anda butuhkan tanpa pengulangan, apakah Anda membutuhkannya?
Ini adalah generator, jadi Anda menggunakannya dalam sesuatu seperti ini:
sumber
sumber
Versi clojure:
sumber
Katakanlah susunan huruf Anda terlihat seperti ini: "ABCDEFGH". Anda memiliki tiga indeks (i, j, k) yang menunjukkan huruf mana yang akan Anda gunakan untuk kata saat ini, Anda mulai dengan:
Pertama Anda bervariasi k, sehingga langkah selanjutnya terlihat seperti itu:
Jika Anda mencapai akhir, Anda melanjutkan dan memvariasikan j lalu k lagi.
Begitu Anda mencapai G, Anda juga mulai memvariasikan i.
Berdasarkan https://stackoverflow.com/a/127898/2628125 , tetapi lebih abstrak, untuk berbagai ukuran pointer.
sumber
Semua dikatakan dan dilakukan di sini datang kode O'caml untuk itu. Algoritma terbukti dari kode ..
sumber
Berikut adalah metode yang memberi Anda semua kombinasi ukuran yang ditentukan dari string panjang acak. Mirip dengan solusi quinmars, tetapi berfungsi untuk beragam input dan k.
Kode dapat diubah untuk membungkus, yaitu 'dab' dari input 'abcd' wk = 3.
Output untuk "abcde":
sumber
kode python pendek, menghasilkan posisi indeks
sumber
Saya membuat solusi dalam SQL Server 2005 untuk ini, dan mempostingnya di situs web saya: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Berikut ini adalah contoh untuk menunjukkan penggunaan:
hasil:
sumber
Inilah proposisi saya di C ++
Saya mencoba untuk memaksakan pembatasan sedikit pada jenis iterator yang saya bisa jadi solusi ini mengasumsikan hanya meneruskan iterator, dan itu bisa menjadi const_iterator. Ini harus bekerja dengan wadah standar apa pun. Dalam kasus di mana argumen tidak masuk akal, ia melempar std :: invalid_argumnent
sumber
Berikut adalah kode yang baru-baru ini saya tulis di Jawa, yang menghitung dan mengembalikan semua kombinasi elemen "num" dari elemen "outOf".
sumber
Solusi Javascript ringkas:
sumber
Algoritma:
Dalam C #:
Mengapa ini berhasil?
Ada bijection antara himpunan bagian dari set elemen-n dan urutan n-bit.
Itu berarti kita bisa mengetahui berapa banyak himpunan bagian dengan menghitung urutan.
misalnya, empat elemen yang ditetapkan di bawah ini dapat diwakili oleh {0,1} X {0, 1} X {0, 1} X {0, 1} (atau 2 ^ 4) urutan yang berbeda.
Jadi - yang harus kita lakukan adalah menghitung 1 hingga 2 ^ n untuk menemukan semua kombinasi. (Kami mengabaikan set kosong.) Selanjutnya, terjemahkan digit ke representasi binernya. Kemudian gantikan elemen dari set Anda untuk bit 'on'.
Jika Anda hanya menginginkan k elemen hasil, hanya cetak ketika k bit 'aktif'.
(Jika Anda ingin semua himpunan bagian alih-alih himpunan panjang k, hapus bagian cnt / kElement.)
(Sebagai buktinya, lihat Matematika courseware gratis MIT untuk Ilmu Komputer, Lehman et al, bagian 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- untuk-komputer-sains-jatuh-2010 / bacaan / )
sumber
Saya telah menulis sebuah kelas untuk menangani fungsi umum untuk bekerja dengan koefisien binomial, yang merupakan jenis masalah yang menjadi masalah Anda. Ia melakukan tugas-tugas berikut:
Keluarkan semua indeks-K dalam format yang bagus untuk setiap N pilih K ke file. Indeks-K dapat diganti dengan string atau huruf yang lebih deskriptif. Metode ini membuat penyelesaian masalah jenis ini cukup sepele.
Mengubah indeks-K menjadi indeks entri yang tepat dalam tabel koefisien binomial yang diurutkan. Teknik ini jauh lebih cepat daripada teknik yang diterbitkan sebelumnya yang mengandalkan iterasi. Itu melakukan ini dengan menggunakan properti matematika yang melekat di Segitiga Pascal. Makalah saya berbicara tentang ini. Saya percaya saya adalah orang pertama yang menemukan dan mempublikasikan teknik ini, tetapi saya bisa saja salah.
Mengubah indeks dalam tabel koefisien binomial yang diurutkan ke indeks K yang sesuai.
Menggunakan metode Mark Dominus untuk menghitung koefisien binomial, yang jauh lebih kecil kemungkinannya untuk meluap dan bekerja dengan jumlah yang lebih besar.
Kelas ditulis dalam .NET C # dan menyediakan cara untuk mengelola objek yang terkait dengan masalah (jika ada) dengan menggunakan daftar generik. Konstruktor kelas ini mengambil nilai bool yang disebut InitTable bahwa ketika true akan membuat daftar generik untuk menampung objek yang akan dikelola. Jika nilai ini salah, maka tidak akan membuat tabel. Tabel tidak perlu dibuat untuk melakukan 4 metode di atas. Metode pengakses disediakan untuk mengakses tabel.
Ada kelas tes terkait yang menunjukkan cara menggunakan kelas dan metodenya. Telah diuji secara ekstensif dengan 2 kasus dan tidak ada bug yang dikenal.
Untuk membaca tentang kelas ini dan mengunduh kodenya, lihat Tablizing The Binomial Coeffieicent .
Seharusnya tidak sulit untuk mengkonversi kelas ini ke C ++.
sumber