Tugas umum dalam pemrograman wawancara (bukan dari pengalaman wawancara saya) adalah untuk mengambil string atau bilangan bulat dan daftar setiap permutasi yang mungkin.
Apakah ada contoh bagaimana hal ini dilakukan dan logika di balik penyelesaian masalah seperti itu?
Saya telah melihat beberapa cuplikan kode tetapi tidak dikomentari / dijelaskan dengan baik sehingga sulit untuk diikuti.
c#
algorithm
permutation
GurdeepS
sumber
sumber
Jawaban:
Pertama-tama: baunya seperti rekursi tentu saja!
Karena Anda juga ingin tahu prinsipnya, saya melakukan yang terbaik untuk menjelaskannya dalam bahasa manusia. Saya pikir rekursi sangat mudah. Anda hanya perlu memahami dua langkah:
Dalam bahasa manusia :
Saya menemukan kodesemu di http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ :
C #
OK, dan sesuatu yang lebih rumit (dan karena itu ditandai #), dari http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : Agak panjang, tapi saya memutuskan untuk menyalinnya ngomong-ngomong, jadi postingan tidak tergantung pada aslinya.
ABC, ACB, BAC, BCA, CAB, CBA.
Kode:
sumber
Swap(ref list[k], ref list[i]);
) tidak perlu.(a[x], a[y]) = (a[y], a[x]);
Itu hanya dua baris kode jika LINQ diizinkan untuk digunakan. Silakan lihat jawaban saya di sini .
EDIT
Inilah fungsi generik saya yang dapat mengembalikan semua permutasi (bukan kombinasi) dari daftar T:
Contoh:
Output - daftar bilangan bulat:
Karena fungsi ini menggunakan LINQ sehingga membutuhkan .net 3.5 atau lebih tinggi.
sumber
const string s = "HALLOWEEN";
var result = GetPermutations(Enumerable.Range(0, s.Length), s.Length).Select(t => t.Select(i => s[i]));
Di sini saya telah menemukan solusinya. Itu ditulis dalam Java, tetapi saya telah mengubahnya menjadi C #. Saya harap ini akan membantu Anda.
Berikut kode dalam C #:
sumber
Rekursi tidak perlu, berikut adalah informasi yang baik tentang solusi ini.
Saya telah menggunakan algoritma ini selama bertahun-tahun, ia memiliki O (N) waktu dan kompleksitas ruang untuk menghitung setiap permutasi .
sumber
O(N-1)
untuk urutan danO(N)
untuk swap, yaituO(N)
. Dan saya masih menggunakan ini dalam produksi tetapi dengan refactor untuk menghasilkan hanya satu permutasi seperti: diGetPermutation(i)
mana0 <= i <= N!-1
. Saya akan dengan senang hati menggunakan sesuatu dengan kinerja yang lebih baik dari ini, jadi bebas untuk memanggil referensi untuk sesuatu yang lebih baik, sebagian besar penggunaan alternatifO(N!)
dalam memori sehingga Anda mungkin memeriksanya juga.Anda dapat menulis fungsi swap Anda untuk bertukar karakter.
Ini disebut permute (string, 0);
sumber
Pertama-tama, set memiliki permutasi, bukan string atau integer, jadi saya hanya akan menganggap Anda berarti "set karakter dalam sebuah string."
Perhatikan bahwa satu set ukuran n memiliki n! n-permutasi.
Kodesemu berikut (dari Wikipedia), dipanggil dengan k = 1 ... n! akan memberikan semua permutasi:
Berikut kode Python yang setara (untuk indeks array berbasis 0):
sumber
k := k / j;
.Versi sedikit dimodifikasi dalam C # yang menghasilkan permutasi yang diperlukan dalam array jenis APA PUN.
sumber
Permutations(vals).ToArray()
maka Anda berakhir dengan referensi N ke array yang sama. Jika Anda ingin dapat menyimpan hasil, Anda harus membuat salinan secara manual. MisalnyaPermutations(values).Select(v => (T[])v.Clone())
sumber
Saya menyukai pendekatan FBryant87 karena sederhana. Sayangnya, ia tidak seperti banyak "solusi" lainnya yang tidak menawarkan semua permutasi atau misalnya integer jika mengandung digit yang sama lebih dari sekali. Ambil 656123 sebagai contoh. Garis:
menggunakan Kecuali akan menyebabkan semua kejadian dihapus, yaitu ketika c = 6, dua digit dihapus dan kita dibiarkan dengan misal 5123. Karena tidak ada solusi yang saya coba selesaikan ini, saya memutuskan untuk mencoba dan menyelesaikannya sendiri oleh FBryant87 's kode sebagai basis. Inilah yang saya pikirkan:
Saya hanya cukup menghapus kejadian pertama yang ditemukan menggunakan .Hapus dan .IndexOf. Tampaknya berfungsi sebagaimana dimaksudkan untuk penggunaan saya setidaknya. Saya yakin itu bisa dibuat lebih pintar.
Satu hal yang perlu diperhatikan: Daftar yang dihasilkan dapat berisi duplikat, jadi pastikan Anda membuat metode pengembalian misalnya HashSet sebagai gantinya atau menghapus duplikat setelah pengembalian menggunakan metode apa pun yang Anda suka.
sumber
Berikut adalah artikel bagus yang mencakup tiga algoritma untuk menemukan semua permutasi, termasuk satu untuk menemukan permutasi berikutnya.
http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
C ++ dan Python masing-masing memiliki fungsi next_permutation dan itertools.permutations .
sumber
Berikut ini adalah implementasi F # yang murni fungsional:
Kinerja dapat sangat ditingkatkan dengan mengubah swap untuk mengambil keuntungan dari sifat array CLR yang bisa berubah, tetapi implementasi ini aman untuk hal terkait dengan larik sumber dan yang mungkin diinginkan dalam beberapa konteks. Juga, untuk array dengan lebih dari 16 elemen int harus diganti dengan tipe dengan presisi yang lebih besar / arbitrer karena faktorial 17 menghasilkan aliran int32.
sumber
Berikut ini adalah solusi sederhana dalam c # menggunakan rekursi,
sumber
Berikut ini adalah fungsi permutasi yang mudah dipahami untuk string dan integer sebagai input. Dengan ini Anda bahkan dapat mengatur panjang output Anda (yang dalam kasus normal itu sama dengan panjang input)
Tali
dan untuk Integer cukup ubah metode pemanggil dan MakePermutations () tetap tidak tersentuh:
contoh 1: GetAllPermutations ("abc", 3); "abc" "acb" "bac" "bca" "cab" "cba"
contoh 2: GetAllPermutations ("abcd", 2); "ab" "ac" "ad" "ba" "bc" "bd" "ca" "cb" "cd" "da" "db" "dc"
contoh 3: GetAllPermutations (486,2); 48 46 84 86 64 68
sumber
Ini adalah fungsi yang akan mencetak semua permutasi. Fungsi ini mengimplementasikan logika Dijelaskan oleh peter.
sumber
Di bawah ini adalah implementasi permutasi saya. Jangan pedulikan nama variabel, karena saya melakukannya untuk bersenang-senang :)
sumber
Inilah contoh tingkat tinggi yang saya tulis yang menggambarkan penjelasan bahasa manusia yang diberikan Peter:
sumber
Jika kinerja dan memori adalah masalah, saya sarankan implementasi yang sangat efisien ini. Menurut algoritma Heap di Wikipedia , itu harus yang tercepat. Semoga sesuai dengan kebutuhan Anda :-)!
Sama seperti perbandingan ini dengan implementasi Linq untuk 10! (termasuk kode):
Linq: 36288000 item dalam 50051 milidetik
sumber
Inilah solusi saya dalam JavaScript (NodeJS). Ide utamanya adalah kita mengambil satu elemen pada satu waktu, "menghapusnya" dari string, memvariasikan sisa karakter, dan memasukkan elemen di depan.
Dan inilah tesnya:
sumber
Berikut adalah solusi paling sederhana yang dapat saya pikirkan:
The
distribute
fungsi mengambil elemen barue
dann
daftar -element dan mengembalikan daftarn+1
daftar yang masing-masing telahe
dimasukkan di tempat yang berbeda. Misalnya, memasukkan10
di masing-masing dari empat tempat yang mungkin dalam daftar[1;2;3]
:The
permute
Fungsi lipatan lebih setiap elemen pada gilirannya mendistribusikan selama permutasi akumulasi sejauh ini, yang berpuncak pada semua permutasi. Sebagai contoh, 6 permutasi daftar[1;2;3]
:Mengubah
fold
kescan
untuk menjaga akumulator menengah menyoroti bagaimana permutasi dihasilkan suatu elemen pada suatu waktu:sumber
Daftar permutasi string. Hindari duplikasi ketika karakter diulang:
sumber
Membangun di atas solusi @ Peter, inilah versi yang menyatakan
Permutations()
metode ekstensi gaya LINQ sederhana yang bekerja pada semuaIEnumerable<T>
.Penggunaan (pada contoh karakter string):
Output:
Atau pada jenis koleksi lainnya:
Output:
sumber
Berikut adalah fungsi yang akan mencetak semua permutasi secara rekursif.
sumber
sumber
Berikut adalah jawaban C # yang sedikit disederhanakan.
Keluaran:
sumber
Ini adalah solusi saya yang mudah bagi saya untuk mengerti
sumber
Berikut ini satu lagi implementasi dari algo yang disebutkan.
sumber
new Permutation().GenerateFor("aba")
keluaranstring[4] { "ab", "baa", "baa", "ab" }
sumber
sumber