κατάλογος όλων των δυνατών μεταθέσεων μιας σειράς Δημιουργία

ψήφοι
143

Πώς θα πάω για τη δημιουργία μια λίστα με όλες τις πιθανές παραλλαγές μιας σειράς μεταξύ x και y χαρακτήρες, που περιέχει μια μεταβλητή λίστα των χαρακτήρων.

Κάθε γλώσσα θα μπορούσε να λειτουργήσει, αλλά θα πρέπει να είναι φορητό.

Δημοσιεύθηκε 02/08/2008 στις 07:57
πηγή χρήστη
Σε άλλες γλώσσες...                            


35 απαντήσεις

ψήφοι
67

Υπάρχουν διάφοροι τρόποι για να γίνει αυτό. Κοινές μέθοδοι χρησιμοποιούν αναδρομή, memoization, ή δυναμικός προγραμματισμός. Η βασική ιδέα είναι ότι μπορείτε να παράγει μια λίστα με όλες τις χορδές του μήκους 1, τότε σε κάθε επανάληψη, για όλα τα έγχορδα που παράγεται στην τελευταία επανάληψη, να προσθέσω ότι κορδόνι συνεχόμενα με κάθε χαρακτήρα στη συμβολοσειρά ξεχωριστά. (Η μεταβλητή δείκτη στην παρακάτω κώδικα παρακολουθεί την έναρξη της τελευταίας και την επόμενη επανάληψη)

Μερικά ψευδοκώδικα:

list = originalString.split('')
index = (0,0)
list = [""]
for iteration n in 1 to y:
  index = (index[1], len(list))
  for string s in list.subset(index[0] to end):
    for character c in originalString:
      list.add(s + c)

που θα πρέπει στη συνέχεια να αφαιρέσετε όλες τις χορδές λιγότερο από χ σε μήκος, θα είναι οι πρώτοι (x-1) * len (originalString) καταχωρήσεις στη λίστα.

Απαντήθηκε 02/08/2008 στις 08:48
πηγή χρήστη

ψήφοι
8

Απλά χτυπημένη αυτό επάνω γρήγορα σε Ruby:

def perms(x, y, possible_characters)
  all = [""]
  current_array = all.clone
  1.upto(y) { |iteration|
    next_array = []
    current_array.each { |string|
      possible_characters.each { |c|
        value = string + c
        next_array.insert next_array.length, value
        all.insert all.length, value
      }
    }
    current_array = next_array
  }
  all.delete_if { |string| string.length < x }
end

Μπορείτε να δείτε σε γλώσσα API για ενσωματωμένες λειτουργίες τύπου μετάθεση, και να είστε σε θέση να γράψω περισσότερα βελτιστοποιημένο κώδικα, αλλά αν οι αριθμοί είναι όλα τόσο ψηλά, δεν είμαι σίγουρος ότι υπάρχει ένα μεγάλο μέρος μιας ανάποδο έχει πολλά αποτελέσματα .

Anyways, η ιδέα πίσω από τον κώδικα είναι να ξεκινήσει με κορδόνι μήκους 0, στη συνέχεια, να παρακολουθείτε όλες τις χορδές του μήκους Ζ, όπου Ζ είναι το τρέχον μέγεθος της επανάληψης. Στη συνέχεια, περνούν από κάθε σειρά και επισυνάπτει κάθε χαρακτήρα σε κάθε χορδή. Τέλος, στο τέλος, αφαιρέστε κάθε που ήταν κάτω από το όριο x και επιστρέφει το αποτέλεσμα.

Εγώ δεν το δοκιμάσετε με δυνητικά νόημα εισόδου (κατάλογος null χαρακτήρα, παράξενα τιμές των x και y, κλπ).

Απαντήθηκε 02/08/2008 στις 08:56
πηγή χρήστη

ψήφοι
4

Δεν είμαι σίγουρος γιατί θα θέλετε να το κάνετε αυτό στην πρώτη θέση. Το σύνολο που προκύπτει για κάθε μετρίως μεγάλες τιμές του x και y θα είναι τεράστια και θα αυξηθεί εκθετικά όσο x ή / και y μεγαλώνουν.

Ας πούμε ότι σας σύνολο των πιθανών χαρακτήρες είναι τα 26 κεφαλαία γράμματα του αλφαβήτου, και να σας ρωτήσω την αίτησή σας για να δημιουργήσει όλες τις παραλλαγές όπου το μήκος = 5. Αν υποθέσουμε ότι δεν τρέχει έξω από τη μνήμη θα έχετε 11.881.376 (ήτοι 26 στην εξουσία 5) σειρές πίσω. Χτύπημα αυτό το μήκος έως 6, και θα πάρετε 308.915.776 χορδές πίσω. Αυτοί οι αριθμοί πάρει οδυνηρά μεγάλο, πολύ γρήγορα.

Εδώ είναι μια λύση έβαλα μαζί σε Java. Θα πρέπει να παρέχει δύο επιχειρήματα χρόνου εκτέλεσης (που αντιστοιχεί στο x και y). Καλα να περνατε.

public class GeneratePermutations {
    public static void main(String[] args) {
        int lower = Integer.parseInt(args[0]);
        int upper = Integer.parseInt(args[1]);

        if (upper < lower || upper == 0 || lower == 0) {
            System.exit(0);
        }

        for (int length = lower; length <= upper; length++) {
            generate(length, "");
        }
    }

    private static void generate(int length, String partial) {
        if (length <= 0) {
            System.out.println(partial);
        } else {
            for (char c = 'a'; c <= 'z'; c++) {
                generate(length - 1, partial + c);
            }
        }
    }
}
Απαντήθηκε 02/08/2008 στις 10:40
πηγή χρήστη

ψήφοι
24

Θα έχετε την ευκαιρία να πάρετε μια πολύ χορδές, αυτό είναι σίγουρο ...

\ sum_ {i = x} ^ y {\ frac {r!} {{(ri)}!}} http://www.codecogs.com/eq.latex?%5Csum_%7Bi=x%7D%5Ey% 20% 7Β% 20% 5Cfrac% 7BR% 7D% 7Β% 7Β (ri)% 7D% 7D% 20% 7D!
Όπου, χ και Υ είναι το πώς μπορείτε να ορίσετε και r είναι ο αριθμός των χαρακτήρων που επιλέγετε από - -αν είμαι εσείς που καταλαβαίνετε σωστά. Θα πρέπει σίγουρα να δημιουργήσει αυτές ανάλογα με τις ανάγκες και να μην πάρει προχειρότητα και να πω, δημιουργούν ένα Powerset και, στη συνέχεια, φιλτράρετε το μήκος των χορδών.

Το παρακάτω σίγουρα δεν είναι ο καλύτερος τρόπος για να δημιουργήσει αυτά, αλλά είναι μια ενδιαφέρουσα άκρη, κανένας-το-λιγότερο.

Knuth (όγκος 4, δεμάτιο 2, 7.2.1.3) μας λέει ότι (s, t) -σύνολα συζευγμένων είναι ισοδύναμο με s + 1 πράγματα ληφθεί t σε έναν χρόνο με την επανάληψη - ένα (s, t) -σύνολα συζευγμένων είναι σημειογραφία χρησιμοποιείται από Knuth που είναι ίση με {t \ επιλέξετε {s + t} http://www.codecogs.com/eq.latex?%7Bt%20%5Cchoose%20%7Bs+t%7D%7D . Μπορούμε να καταλάβουμε αυτό έξω από την πρώτη δημιουργία κάθε (s, t) -σύνολα συζευγμένων σε δυαδική μορφή (έτσι, του μήκους (s + t)) και μετρώντας τον αριθμό των 0 στα αριστερά κάθε 1.

10001000011101 -> γίνεται η μετάθεση: {0, 3, 4, 4, 4, 1}

Απαντήθηκε 05/08/2008 στις 05:57
πηγή χρήστη

ψήφοι
2

Σε ρουμπίνι:

str = "a"
100_000_000.times {puts str.next!}

Είναι αρκετά γρήγορο, αλλά πρόκειται να πάρει κάποιο χρόνο =). Φυσικά, μπορείτε να ξεκινήσετε σε «aaaaaaaa» αν οι σύντομες σειρές δεν είναι ενδιαφέρουσες για εσάς.

Θα ήθελα να έχουν παρερμηνεύσει το πραγματικό ερώτημα αν και - σε μία από τις θέσεις που ακουγόταν σαν απλά χρειάζεται μια βιβλιοθήκη bruteforce της χορδές, αλλά το κύριο ερώτημα που ακούγεται σαν να πρέπει να permutate μια συγκεκριμένη σειρά.

Το πρόβλημά σας είναι κάπως παρόμοιο με αυτό: http://beust.com/weblog/archives/000491.html (κατάλογος όλα ακέραιοι με την οποία κανένα από τα ψηφία επαναλαμβάνονται, η οποία οδήγησε σε ένα σωρό γλώσσες που επίλυσης, με το OCaml άντρας που χρησιμοποιούν παραλλαγές, και κάποιος τύπος java χρησιμοποιώντας μια ακόμη λύση).

Απαντήθηκε 15/09/2008 στις 18:32
πηγή χρήστη

ψήφοι
7

Αυτή είναι μια μετάφραση της έκδοσης Ruby Mike, σε Common Lisp:

(defun perms (x y original-string)
  (loop with all = (list "")
        with current-array = (list "")
        for iteration from 1 to y
        do (loop with next-array = nil
                 for string in current-array
                 do (loop for c across original-string
                          for value = (concatenate 'string string (string c))
                          do (push value next-array)
                             (push value all))
                    (setf current-array (reverse next-array)))
        finally (return (nreverse (delete-if #'(lambda (el) (< (length el) x)) all)))))

Και μια άλλη εκδοχή, ελαφρώς μικρότερη και χρησιμοποιώντας περισσότερες δυνατότητες διευκόλυνσης βρόχο:

(defun perms (x y original-string)
  (loop repeat y
        collect (loop for string in (or (car (last sets)) (list ""))
                      append (loop for c across original-string
                                   collect (concatenate 'string string (string c)))) into sets
        finally (return (loop for set in sets
                              append (loop for el in set when (>= (length el) x) collect el)))))
Απαντήθηκε 16/09/2008 στις 06:15
πηγή χρήστη

ψήφοι
0

Αν και αυτό δεν απαντά στην ερώτησή σας ακριβώς, εδώ είναι ένας τρόπος για να δημιουργήσει κάθε μετάθεση των γραμμάτων από τον αριθμό των χορδών του ίδιου μήκους: π.χ., αν τα λόγια σας ήταν «καφέ», «joomla» και «moodle», μπορείτε να αναμένουμε εξόδου, όπως "coodle", "joodee", "joffle", κ.λπ.

Βασικά, ο αριθμός των συνδυασμών είναι ο (αριθμός λέξεων) με τη δύναμη του (αριθμός των γραμμάτων κάθε λέξης). Έτσι, επιλέγουν έναν τυχαίο αριθμό μεταξύ 0 και τον αριθμό των συνδυασμών - 1, μετατρέψετε αυτόν τον αριθμό στη βάση (αριθμός λέξεων), στη συνέχεια, χρησιμοποιήστε κάθε ψηφίο του αριθμού ως ένδειξη για την οποία λέξη για να κάνει το επόμενο γράμμα από.

π.χ.: στο παραπάνω παράδειγμα. 3 λέξεις, 6 γράμματα = 729 συνδυασμούς. Επιλέξτε έναν τυχαίο αριθμό: 465. Μετατροπή σε βασίσει 3: 122020. Πάρτε το πρώτο γράμμα από την λέξη 1, 2 από την λέξη 2, 3 από την λέξη 2, 4 από στόμα σε 0 ... και θα πάρει ... «joofle».

Αν ήθελε όλες τις παραλλαγές, μόλις βρόχο από το 0 έως το 728. Φυσικά, αν είστε απλά επιλέγοντας μία τυχαία τιμή, μια πολύ απλούστερη λιγότερο σύγχυση τρόπος θα ήταν να βρόχο πάνω από τα γράμματα. Η μέθοδος αυτή επιτρέπει να αποφευχθεί η αναδρομή, θα πρέπει να θέλετε όλες τις παραλλαγές, καθώς θα σας κάνει να μοιάζουν με ξέρετε Μαθηματικά (tm) !

Εάν ο αριθμός των συνδυασμών είναι υπερβολική, μπορείτε να το σπάσει σε μια σειρά από μικρότερες λέξεις και ενώσετε τους στο τέλος.

Απαντήθηκε 16/09/2008 στις 06:33
πηγή χρήστη

ψήφοι
7

Αναδρομικές διάλυμα σε C ++

int main (int argc, char * const argv[]) {
        string s = "sarp";
        bool used [4];
        permute(0, "", used, s);
}

void permute(int level, string permuted, bool used [], string &original) {
    int length = original.length();

    if(level == length) { // permutation complete, display
        cout << permuted << endl;
    } else {
        for(int i=0; i<length; i++) { // try to add an unused character
            if(!used[i]) {
                used[i] = true;
                permute(level+1, original[i] + permuted, used, original); // find the permutations starting with this string
                used[i] = false;
            }
        }
}
Απαντήθηκε 29/09/2008 στις 02:34
πηγή χρήστη

ψήφοι
7

Εδώ είναι μια απλή λέξη, C # αναδρομική λύση:

Μέθοδος:

public ArrayList CalculateWordPermutations(string[] letters, ArrayList words, int index)
        {
            bool finished = true;
            ArrayList newWords = new ArrayList();
            if (words.Count == 0)
            {
                foreach (string letter in letters)
                {
                    words.Add(letter);
                }
            }

            for(int j=index; j<words.Count; j++)
            {
                string word = (string)words[j];
                for(int i =0; i<letters.Length; i++)
                {
                    if(!word.Contains(letters[i]))
                    {
                        finished = false;
                        string newWord = (string)word.Clone();
                        newWord += letters[i];
                        newWords.Add(newWord);
                    }
                }
            }

            foreach (string newWord in newWords)
            {   
                words.Add(newWord);
            }

            if(finished  == false)
            {
                CalculateWordPermutations(letters, words, words.Count - newWords.Count);
            }
            return words;
        }

Κλήση:

string[] letters = new string[]{"a","b","c"};
ArrayList words = CalculateWordPermutations(letters, new ArrayList(), 0);
Απαντήθηκε 20/10/2008 στις 01:17
πηγή χρήστη

ψήφοι
12

Μπορείτε να δείτε στις ομάδες « Αποδοτικές Απαριθμώντας τα υποσύνολα ενός συνόλου », η οποία περιγράφει έναν αλγόριθμο για να κάνει από την πλευρά της ό, τι θέλετε - γρήγορα να δημιουργήσει όλα τα υποσύνολα του N χαρακτήρες από το μήκος x έως y. Περιέχει μια εφαρμογή σε C.

Για κάθε υποσύνολο, θα πρέπει ακόμα να δημιουργήσει όλες τις παραλλαγές. Για παράδειγμα, αν ήθελε 3 χαρακτήρες από το «ABCDE», ο αλγόριθμος αυτός θα σας δώσει «abc», «Abe» «abd» ... αλλά θα πρέπει να μεταθέτει ο καθένας να πάρει «ACB», «bac», "BCA", κ.λπ.

Απαντήθηκε 14/11/2008 στις 20:36
πηγή χρήστη

ψήφοι
7

Στην Perl, αν θέλετε να περιορίσετε τον εαυτό σας στην πεζά αλφάβητο, μπορείτε να το κάνετε αυτό:

my @result = ("a" .. "zzzz");

Αυτό δίνει όλες τις πιθανές σειρές μεταξύ 1 και 4 χαρακτήρες χρησιμοποιώντας πεζούς χαρακτήρες. Για κεφαλαία, αλλάξτε "a"σε "A"και "zzzz"σε "ZZZZ".

Για μικτή περίπτωση γίνεται πολύ πιο δύσκολο, και ίσως να μην εφικτό με μία από τις ενσωματωμένες φορείς της Perl έτσι.

Απαντήθηκε 15/02/2009 στις 11:02
πηγή χρήστη

ψήφοι
12

Μερικά κώδικα εργασίας που βασίζεται σε Java σε απάντηση Sarp είναι :

public class permute {

    static void permute(int level, String permuted,
                    boolean used[], String original) {
        int length = original.length();
        if (level == length) {
            System.out.println(permuted);
        } else {
            for (int i = 0; i < length; i++) {
                if (!used[i]) {
                    used[i] = true;
                    permute(level + 1, permuted + original.charAt(i),
                       used, original);
                    used[i] = false;
                }
            }
        }
    }

    public static void main(String[] args) {
        String s = "hello";
        boolean used[] = {false, false, false, false, false};
        permute(0, "", used, s);
    }
}
Απαντήθηκε 04/04/2010 στις 19:18
πηγή χρήστη

ψήφοι
12

Εδώ είναι μια απλή λύση σε C #.

Παράγει μόνο τις ξεχωριστές παραλλαγές μιας συγκεκριμένης σειράς.

    static public IEnumerable<string> permute(string word)
    {
        if (word.Length > 1)
        {

            char character = word[0];
            foreach (string subPermute in permute(word.Substring(1)))
            {

                for (int index = 0; index <= subPermute.Length; index++)
                {
                    string pre = subPermute.Substring(0, index);
                    string post = subPermute.Substring(index);

                    if (post.Contains(character))
                            continue;                       

                    yield return pre + character + post;
                }

            }
        }
        else
        {
            yield return word;
        }
    }
Απαντήθηκε 05/07/2010 στις 10:06
πηγή χρήστη

ψήφοι
5
import java.util.*;

public class all_subsets {
    public stati