एक स्ट्रिंग के सभी संभावित क्रमपरिवर्तन की सूची बनाएँ


159

मैं वर्णों की चर सूची वाली लंबाई में x और y वर्णों के बीच स्ट्रिंग के सभी संभावित क्रमपरिवर्तन की सूची बनाने के बारे में कैसे जाऊंगा।

कोई भी भाषा काम करेगी, लेकिन यह पोर्टेबल होनी चाहिए।


जवाबों:


70

इसे करने बहुत सारे तरीके हैं। सामान्य विधियाँ पुनरावर्तन, संस्मरण या गतिशील प्रोग्रामिंग का उपयोग करती हैं। मूल विचार यह है कि आप लंबाई 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 से कम के सभी तारों को निकालने की आवश्यकता होगी, वे सूची में पहले (x-1) * लेन (ओरिजिनल स्ट्रिंग) प्रविष्टियाँ होंगे।


4
पहले तत्वों की सूची को क्यों संग्रहीत करें, और फिर इसे साफ़ करें? (छद्मकोश में पंक्ति 1 और 3 का उल्लेख)।
होवार्ड गीथस

6
Y (पंक्ति 4) क्या है?
जसीम

7
@ जसीम इस सवाल से: "x और y वर्णों के बीच एक स्ट्रिंग के सभी संभावित क्रमांकन "
ck_

39

बैकट्रैकिंग का उपयोग करना बेहतर है

#include <stdio.h>
#include <string.h>

void swap(char *a, char *b) {
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void print(char *a, int i, int n) {
    int j;
    if(i == n) {
        printf("%s\n", a);
    } else {
        for(j = i; j <= n; j++) {
            swap(a + i, a + j);
            print(a, i + 1, n);
            swap(a + i, a + j);
        }
    }
}

int main(void) {
    char a[100];
    gets(a);
    print(a, 0, strlen(a) - 1);
    return 0;
}

3
सर्वश्रेष्ठ समाधान सदाबहार
ग्रोइनमैन

25

आपको बहुत सारे तार मिलने जा रहे हैं, यह सुनिश्चित करने के लिए ...

\ Sum_ {मैं = एक्स} ^ y {\ frac {r!} {{(री)}!}}
जहाँ x और y यह है कि आप उन्हें कैसे परिभाषित करते हैं और r हम कितने अक्षर से चुन रहे हैं - यदि मैं आपको सही ढंग से समझ रहा हूँ। आपको निश्चित रूप से इन्हें उत्पन्न करना चाहिए और मैला नहीं होना चाहिए और कहना चाहिए, एक पावरसेट उत्पन्न करें और फिर स्ट्रिंग्स की लंबाई को फ़िल्टर करें।

निम्नलिखित निश्चित रूप से इन उत्पन्न करने का सबसे अच्छा तरीका नहीं है, लेकिन यह एक तरफ एक दिलचस्प है, कोई नहीं-कम।

नुथ (खंड 4, 2, 7.2.1.3) हमें बताता है कि (एस, टी) -कम्बिनेशन एस + 1 चीजों के बराबर है जो एक समय में दोहराव के साथ लिया जाता है - (ए, टी) -combination संकेतन का उपयोग किया जाता है नथ जो बराबर है {t \ _ {s + t} चुनें । हम पहले बाइनरी रूप में प्रत्येक (एस, टी) -combination (इसलिए, लंबाई (एस + टी)) और प्रत्येक 1 के बाईं ओर 0 की संख्या की गिनती करके यह पता लगा सकते हैं।

10001000011101 -> क्रमचय बनता है: {0, 3, 4, 4, 4, 1}


15

नथ, पायथन उदाहरण के अनुसार गैर पुनरावर्ती समाधान:

def nextPermutation(perm):
    k0 = None
    for i in range(len(perm)-1):
        if perm[i]<perm[i+1]:
            k0=i
    if k0 == None:
        return None

    l0 = k0+1
    for i in range(k0+1, len(perm)):
        if perm[k0] < perm[i]:
            l0 = i

    perm[k0], perm[l0] = perm[l0], perm[k0]
    perm[k0+1:] = reversed(perm[k0+1:])
    return perm

perm=list("12345")
while perm:
    print perm
    perm = nextPermutation(perm)

2
दरअसल, यह तब काम नहीं करता है जब स्ट्रिंग को सॉर्ट नहीं किया जाता है। यदि आप "54321"केवल एक स्ट्रिंग के साथ कोशिश करते हैं (स्वयं) दिखाया गया है।
टनजो

1
यह दिलचस्प है कि nextPermutation()यह स्टेटलेस है - यह केवल इनपुट को क्रमबद्ध करने के लिए लेता है और अनुक्रमित पुनरावृति से पुनरावृत्ति में बनाए नहीं रखा जाता है। यह ऐसा मानकर आरंभ करने में सक्षम है कि प्रारंभिक इनपुट को क्रमबद्ध किया गया था और अनुक्रमणिका ( k0और l0) को खोजने के आधार पर, जहां ऑर्डर बनाए रखा गया है। "54321" -> "12345" जैसे इनपुट को छाँटने से इस एल्गोरिथम को सभी अपेक्षित क्रमपरिवर्तन खोजने में मदद मिलेगी। लेकिन चूंकि यह उन सभी अनुक्रमों के लिए उन अनुक्रमणिकाओं को फिर से खोजने के लिए अतिरिक्त काम करता है जो इसे उत्पन्न करते हैं, इस गैर-पुनरावृत्ति को करने के अधिक कुशल तरीके हैं।
स्पाकार्की 21

13

आप देख सकते हैं " सेट के सबलेट्स को कुशलतापूर्वक एनुमरेट करना , जो एक एल्गोरिथ्म का वर्णन करता है कि आप क्या चाहते हैं - जल्दी से लंबाई x से y तक एन वर्णों के सभी सबसेट उत्पन्न करते हैं। इसमें C का कार्यान्वयन शामिल है।

प्रत्येक सबसेट के लिए, आपको अभी भी सभी क्रमचय उत्पन्न करने होंगे। उदाहरण के लिए यदि आप "abcde" से 3 वर्ण चाहते थे, तो यह एल्गोरिथ्म आपको "abc", "abd", "abe" देगा ... लेकिन आपको "acb", "bac" प्राप्त करने के लिए प्रत्येक को अनुमति देनी होगी, "बीका", आदि।


13

सर्प के उत्तर पर आधारित कुछ कार्य जावा कोड :

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);
    }
}

एक टिप्पणी के रूप में, ध्यान दें कि बार-बार वर्ण वाले स्ट्रिंग के लिए यह अनूठे क्रमपरिवर्तन का उत्पादन नहीं करेगा। यह एक हैश के साथ हल किया जा सकता है, लेकिन यह लंबे तारों के साथ एक समस्या हो सकती है।
ग्लेन

8
आप स्ट्रिंग्स के बजाय चार सरणियों का उपयोग करना चाह सकते हैं ताकि यह रन तेज़ हो जाए क्योंकि स्ट्रिंग्स जावा में अपरिवर्तनीय हैं।
अभिजीत कासनिया जूल

13

यहाँ 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;
        }
    }

12

यहाँ बहुत सारे अच्छे उत्तर हैं। मैं C ++ में एक बहुत ही सरल पुनरावर्ती समाधान भी सुझाता हूं।

#include <string>
#include <iostream>

template<typename Consume>
void permutations(std::string s, Consume consume, std::size_t start = 0) {
    if (start == s.length()) consume(s);
    for (std::size_t i = start; i < s.length(); i++) {
        std::swap(s[start], s[i]);
        permutations(s, consume, start + 1);
    }
}

int main(void) {
    std::string s = "abcd";
    permutations(s, [](std::string s) {
        std::cout << s << std::endl;
    });
}

नोट : बार-बार वर्णों के साथ तार अद्वितीय क्रमपरिवर्तन उत्पन्न नहीं करेंगे।


9

मैं सिर्फ रूबी में यह जल्दी मार पड़ी है:

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

आप क्रमपरिवर्तन प्रकार के कार्यों में निर्मित के लिए भाषा एपीआई में देख सकते हैं, और आप अधिक अनुकूलित कोड लिखने में सक्षम हो सकते हैं, लेकिन यदि संख्या सभी उच्च हैं, तो मुझे यकीन नहीं है कि बहुत सारे परिणाम होने के आसपास एक रास्ता है ।

वैसे भी, कोड के पीछे विचार लंबाई 0 के स्ट्रिंग के साथ शुरू होता है, फिर लंबाई Z के सभी तारों पर नज़र रखें जहां Z पुनरावृत्ति में वर्तमान आकार है। फिर, प्रत्येक स्ट्रिंग पर जाएं और प्रत्येक स्ट्रिंग पर प्रत्येक वर्ण को जोड़ दें। अंत में, एक्स थ्रेशोल्ड के नीचे से किसी को हटा दें और परिणाम वापस करें।

मैंने इसे संभावित अर्थहीन इनपुट (अशक्त चरित्र सूची, एक्स और वाई के अजीब मूल्यों आदि) के साथ परीक्षण नहीं किया।


11
यह कोड गलत है। यह अमान्य क्रमपरिवर्तन उत्पन्न करेगा, जैसे कि बार-बार वर्ण वाले। उदाहरण के लिए, स्ट्रिंग "एबीसी" के लिए, यह आकार 3 के इन क्रमपरिवर्तन को उत्पन्न करता है: ["आ", "आब", "एएसी", "अबा", "अब्ब", "एबीसी", "अका", "एसीबी", "एसीसी", "बा", "बाबा", "बाक", "बबा", "बब्ब", "बबक", "बका", "बीसीबी", "बीसीसी", "केएए", "कैब", "कैक" "," cba "," cbb "," cbc "," cca "," ccb "," ccc "]। यह गलत है।
pmc255

8

यह कॉमन लिस्प में माइक के रूबी संस्करण का अनुवाद है:

(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)))))

8

यहाँ एक सरल शब्द है 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);

8

... और यहाँ C संस्करण है:

void permute(const char *s, char *out, int *used, int len, int lev)
{
    if (len == lev) {
        out[lev] = '\0';
        puts(out);
        return;
    }

    int i;
    for (i = 0; i < len; ++i) {
        if (! used[i])
            continue;

        used[i] = 1;
        out[lev] = s[i];
        permute(s, out, used, len, lev + 1);
        used[i] = 0;
    }
    return;
}

8

परमिट (ABC) -> एपरम (BC) -> एपरम [B.perm (C)] -> एपरम [( * B C), (C B * )] -> [( * A BC ), (बी सी), (BC ए * ), ( * एक सीबी), (सी बी), (सीबी ए * )] डुप्लिकेट जब प्रत्येक वर्णमाला की जांच डालने को देखने के लिए दूर करने के लिए करता है, तो एक ही वर्णमाला के साथ पिछले स्ट्रिंग समाप्त होता है (क्यों? -सेक्स)

public static void main(String[] args) {

    for (String str : permStr("ABBB")){
        System.out.println(str);
    }
}

static Vector<String> permStr(String str){

    if (str.length() == 1){
        Vector<String> ret = new Vector<String>();
        ret.add(str);
        return ret;
    }

    char start = str.charAt(0);
    Vector<String> endStrs = permStr(str.substring(1));
    Vector<String> newEndStrs = new Vector<String>();
    for (String endStr : endStrs){
        for (int j = 0; j <= endStr.length(); j++){
            if (endStr.substring(0, j).endsWith(String.valueOf(start)))
                break;
            newEndStrs.add(endStr.substring(0, j) + String.valueOf(start) + endStr.substring(j));
        }
    }
    return newEndStrs;
}

सभी क्रमपरिवर्तन संट्स डुप्लिकेट प्रिंट करता है


8

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;
            }
        }
}

7

पर्ल में, यदि आप अपने आप को निचली वर्णमाला तक सीमित रखना चाहते हैं, तो आप ऐसा कर सकते हैं:

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

यह लोअरकेस वर्णों का उपयोग करके 1 और 4 वर्णों के बीच सभी संभावित तार देता है। अपरकेस के लिए, परिवर्तन "a"करने के लिए"A" और के "zzzz"लिए"ZZZZ"

मिश्रित-मामले के लिए यह बहुत कठिन हो जाता है, और शायद पर्ल के बिलिन ऑपरेटरों में से एक के साथ ऐसा करने योग्य नहीं है।


7

रूबी का जवाब है कि काम करता है:

class String
  def each_char_with_index
    0.upto(size - 1) do |index|
      yield(self[index..index], index)
    end
  end
  def remove_char_at(index)
    return self[1..-1] if index == 0
    self[0..(index-1)] + self[(index+1)..-1]
  end
end

def permute(str, prefix = '')
  if str.size == 0
    puts prefix
    return
  end
  str.each_char_with_index do |char, index|
    permute(str.remove_char_at(index), prefix + char)
  end
end

# example
# permute("abc")

रूबी में एक फैंसी एक लाइनर के लिए: stackoverflow.com/questions/5773961/…
dojosto

6
import java.util.*;

public class all_subsets {
    public static void main(String[] args) {
        String a = "abcd";
        for(String s: all_perm(a)) {
            System.out.println(s);
        }
    }

    public static Set<String> concat(String c, Set<String> lst) {
        HashSet<String> ret_set = new HashSet<String>();
        for(String s: lst) {
            ret_set.add(c+s);
        }
        return ret_set;
    }

    public static HashSet<String> all_perm(String a) {
        HashSet<String> set = new HashSet<String>();
        if(a.length() == 1) {
            set.add(a);
        } else {
            for(int i=0; i<a.length(); i++) {
                set.addAll(concat(a.charAt(i)+"", all_perm(a.substring(0, i)+a.substring(i+1, a.length()))));
            }
        }
        return set;
    }
}

6

निम्नलिखित जावा पुनरावर्तन किसी दिए गए स्ट्रिंग के सभी क्रमांकन को प्रिंट करता है:

//call it as permut("",str);

public void permut(String str1,String str2){
    if(str2.length() != 0){
        char ch = str2.charAt(0);
        for(int i = 0; i <= str1.length();i++)
            permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                     str2.substring(1,str2.length()));
    }else{
    System.out.println(str1);
    }
}

उपरोक्त "permut" विधि का अद्यतन संस्करण है जो n बनाता है! (n factorial) उपरोक्त विधि की तुलना में कम पुनरावर्ती कॉल

//call it as permut("",str);

public void permut(String str1,String str2){
   if(str2.length() > 1){
       char ch = str2.charAt(0);
       for(int i = 0; i <= str1.length();i++)
          permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }else{
    char ch = str2.charAt(0);
    for(int i = 0; i <= str1.length();i++)
        System.out.println(str1.substring(0,i) + ch +    str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }
}

यह सबसे साफ समाधान है, और मुझे विश्वास है कि मैंने इसे "क्रैकिंग द क्रोकिंग इंटरव्यू" पुस्तक में देखा है
ताओ झांग

1
@TaoZhang पूरक के लिए धन्यवाद, मैंने इसे कहीं से भी कॉपी नहीं किया हालांकि यह संभव है कि किसी ने समान अहंकार बनाया हो। वैसे भी मैंने कम पुनरावर्ती कॉल के लिए ऊपर कोड अपडेट किया है
रामी

5

मुझे यकीन नहीं है कि आप पहली बार में ऐसा क्यों करना चाहेंगे। एक्स और वाई के किसी भी बड़े बड़े मूल्यों के लिए परिणामी सेट बहुत बड़ा होगा, और एक्स और / या वाई के रूप में तेजी से बड़ा हो जाएगा।

कहते हैं कि आपके वर्णों का सेट संभव वर्णमाला के 26 लोअरकेस अक्षर हैं, और आप अपने आवेदन को उन सभी अनुमतियों को उत्पन्न करने के लिए कहते हैं जहां लंबाई = 5. मान लें कि आप स्मृति से बाहर नहीं भागते हैं, तो आपको 11,881,376 (यानी 26 की शक्ति प्राप्त होगी) 5) वापस तार। उस लम्बाई को 6 तक उछालें, और आपको 308,915,776 तार वापस मिलेंगे। ये संख्या बहुत तेज़ी से दर्द करती है।

यहाँ एक समाधान है जिसे मैंने जावा में एक साथ रखा है। आपको दो रनटाइम तर्क (एक्स और वाई के अनुरूप) प्रदान करने की आवश्यकता होगी। मज़े करो।

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);
            }
        }
    }
}

लंबे समय से लेकिन आप उन्हें दोहराव के साथ पैदा नहीं कर रहे हैं?
काकीरा

5

यहाँ एक गैर-पुनरावर्ती संस्करण है, जो कि जावास्क्रिप्ट में आया था। यह नुथ के गैर-पुनरावर्ती ऊपर से आधारित नहीं है, हालांकि इसमें तत्व स्वैपिंग में कुछ समानताएं हैं। मैंने 8 तत्वों तक के इनपुट सरणियों के लिए इसकी शुद्धता को सत्यापित किया है।

एक त्वरित अनुकूलन outएरे को प्री-फ्लाइंग और टालना होगा push()

मूल विचार है:

  1. एकल स्रोत सरणी को देखते हुए, सरणियों का पहला नया सेट उत्पन्न करें जो बदले में प्रत्येक बाद के तत्व के साथ पहले तत्व को स्वैप करता है, हर बार अन्य तत्वों को छोड़ देता है। उदाहरण: 1234 दिया गया, 1234, 2134, 3214, 4231 उत्पन्न करें।

  2. नए पास के लिए बीज के रूप में पिछले पास से प्रत्येक सरणी का उपयोग करें, लेकिन पहले तत्व को स्वैप करने के बजाय, दूसरे तत्व के साथ दूसरे तत्व को स्वैप करें। इस समय, आउटपुट में मूल सरणी शामिल न करें।

  3. चरण 2 तक दोहराएं।

यहाँ कोड नमूना है:

function oxe_perm(src, depth, index)
{
    var perm = src.slice();     // duplicates src.
    perm = perm.split("");
    perm[depth] = src[index];
    perm[index] = src[depth];
    perm = perm.join("");
    return perm;
}

function oxe_permutations(src)
{
    out = new Array();

    out.push(src);

    for (depth = 0; depth < src.length; depth++) {
        var numInPreviousPass = out.length;
        for (var m = 0; m < numInPreviousPass; ++m) {
            for (var n = depth + 1; n < src.length; ++n) {
                out.push(oxe_perm(out[m], depth, n));
            }
        }
    }

    return out;
}

3

रूबी में:

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

यह काफी तेज है, लेकिन इसमें कुछ समय लगने वाला है =)। बेशक, आप "आआआआआआ" शुरू कर सकते हैं यदि छोटे तार आपके लिए दिलचस्प नहीं हैं।

मैंने वास्तविक प्रश्न का गलत अर्थ निकाला हो सकता है - किसी एक पोस्ट में ऐसा लगता है जैसे कि आपको स्ट्रिंग्स के एक ब्रूटफोर्स लाइब्रेरी की आवश्यकता है, लेकिन मुख्य प्रश्न में यह लगता है कि आपको किसी विशेष स्ट्रिंग को क्रमबद्ध करने की आवश्यकता है।

आपकी समस्या कुछ हद तक इसी तरह की है: http://beust.com/weblog/archives/000491.html (सभी पूर्णांकों की सूची जिसमें कोई भी अंक खुद को दोहराता नहीं है, जिसके परिणामस्वरूप संपूर्ण भाषाओं को हल करने में बहुत कुछ मिला, ocaml लड़का क्रमपरिवर्तन का उपयोग कर रहा है, और कुछ जावा व्यक्ति अभी तक एक अन्य समाधान का उपयोग कर रहा है)।


आपके प्रस्ताव के साथ एक मुद्दा यह है कि str.next! सभी मुद्रण योग्य वर्णों पर पुनरावृति नहीं होगी। आपका उदाहरण केवल लोअरकेस अक्षर उत्पन्न करेगा - कोई विराम चिह्न, या पूंजी पत्र नहीं।
जर्सन

3

मुझे आज इसकी आवश्यकता थी, और हालांकि पहले से दिए गए उत्तर ने मुझे सही दिशा में इंगित किया, वे काफी नहीं थे जो मैं चाहता था।

हीप की विधि का उपयोग करके यहां एक कार्यान्वयन है। सरणी की लंबाई कम से कम 3 होनी चाहिए और व्यावहारिक विचारों के लिए 10 या उससे अधिक नहीं होनी चाहिए, जो आप करना चाहते हैं, धैर्य और घड़ी की गति पर निर्भर करता है।

इससे पहले कि आप अपने लूप में प्रवेश करें, Perm(1 To N)पहले क्रमपरिवर्तन के साथ प्रारंभ करें, Stack(3 To N)शून्य के साथ *, और ** के Levelसाथ 2। लूप कॉल के अंत में NextPerm, जब हम कर रहे हैं झूठे वापस आ जाएगी।

* VB आपके लिए वही करेगा।

** आप इसे अनावश्यक बनाने के लिए नेक्स्टपर्म को थोड़ा बदल सकते हैं, लेकिन यह इस तरह से स्पष्ट है।

Option Explicit

Function NextPerm(Perm() As Long, Stack() As Long, Level As Long) As Boolean
Dim N As Long
If Level = 2 Then
    Swap Perm(1), Perm(2)
    Level = 3
Else
    While Stack(Level) = Level - 1
        Stack(Level) = 0
        If Level = UBound(Stack) Then Exit Function
        Level = Level + 1
    Wend
    Stack(Level) = Stack(Level) + 1
    If Level And 1 Then N = 1 Else N = Stack(Level)
    Swap Perm(N), Perm(Level)
    Level = 2
End If
NextPerm = True
End Function

Sub Swap(A As Long, B As Long)
A = A Xor B
B = A Xor B
A = A Xor B
End Sub

'This is just for testing.
Private Sub Form_Paint()
Const Max = 8
Dim A(1 To Max) As Long, I As Long
Dim S(3 To Max) As Long, J As Long
Dim Test As New Collection, T As String
For I = 1 To UBound(A)
    A(I) = I
Next
Cls
ScaleLeft = 0
J = 2
Do
    If CurrentY + TextHeight("0") > ScaleHeight Then
        ScaleLeft = ScaleLeft - TextWidth(" 0 ") * (UBound(A) + 1)
        CurrentY = 0
        CurrentX = 0
    End If
    T = vbNullString
    For I = 1 To UBound(A)
        Print A(I);
        T = T & Hex(A(I))
    Next
    Print
    Test.Add Null, T
Loop While NextPerm(A, S, J)
J = 1
For I = 2 To UBound(A)
    J = J * I
Next
If J <> Test.Count Then Stop
End Sub

अन्य तरीकों का वर्णन विभिन्न लेखकों द्वारा किया गया है। नुथ दो का वर्णन करता है, एक शाब्दिक क्रम देता है, लेकिन जटिल और धीमा है, दूसरे को सादे परिवर्तनों की विधि के रूप में जाना जाता है। जी गाओ और डियानजुन वांग ने एक दिलचस्प पेपर भी लिखा।


2

अजगर में यह कोड, जब allowed_charactersसेट टू [0,1]और 4 वर्ण अधिकतम के साथ कहा जाता है , 2 ^ 4 परिणाम उत्पन्न करेगा:

['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

def generate_permutations(chars = 4) :

#modify if in need!
    allowed_chars = [
        '0',
        '1',
    ]

    status = []
    for tmp in range(chars) :
        status.append(0)

    last_char = len(allowed_chars)

    rows = []
    for x in xrange(last_char ** chars) :
        rows.append("")
        for y in range(chars - 1 , -1, -1) :
            key = status[y]
            rows[x] = allowed_chars[key] + rows[x]

        for pos in range(chars - 1, -1, -1) :
            if(status[pos] == last_char - 1) :
                status[pos] = 0
            else :
                status[pos] += 1
                break;

    return rows

import sys


print generate_permutations()

आशा है कि यह आपके लिए उपयोगी है। किसी भी वर्ण के साथ काम करता है, न केवल संख्या


यह क्रमपरिवर्तन नहीं है, लेकिन उप-चयन, यानी ABC और 001 = C, जबकि एक वैध क्रमपरिवर्तन में सभी तीन वर्ण होने चाहिए।
Schultz9999

उह? क्षमा करें, मुझे समझ नहीं आ रहा है कि आप क्या कहते हैं। यदि आप इसे ठीक करते हैं तो एक निश्चित संस्करण छोड़ देते हैं, मैं समुदाय को इस बात को
बताऊंगा


0

यद्यपि यह आपके प्रश्न का सटीक उत्तर नहीं देता है, यहाँ एक ही लंबाई के कई तार से अक्षरों के प्रत्येक क्रमपरिवर्तन को उत्पन्न करने का एक तरीका है: उदाहरण के लिए, यदि आपके शब्द "कॉफ़ी", "जुमला" और "मूडल" हैं, तो आप कर सकते हैं उम्मीद है कि "कूडल", "जोदे", "जोफले", आदि जैसे उत्पादन।

मूल रूप से, संयोजनों की संख्या (शब्दों की संख्या) की शक्ति (प्रति शब्द अक्षरों की संख्या) है। तो, 0 और संयोजनों की संख्या के बीच एक यादृच्छिक संख्या चुनें - 1, उस संख्या को आधार (शब्दों की संख्या) में परिवर्तित करें, फिर उस संख्या के प्रत्येक अंक को संकेतक के रूप में उपयोग करें जिसके लिए अगले अक्षर से शब्द लेना है।

उदाहरण के लिए: उपरोक्त उदाहरण में। 3 शब्द, 6 अक्षर = 729 संयोजन। एक यादृच्छिक संख्या चुनें: 465. आधार 3 में परिवर्तित करें: 122020. शब्द 1 से पहला अक्षर लें, 2 शब्द से 2, 3 से शब्द 2, 4 से शब्द 0 ... और आपको मिलता है ... "joofle"।

यदि आप सभी क्रमपरिवर्तन चाहते थे, तो बस 0 से 728 तक लूप करें। बेशक, यदि आप सिर्फ एक यादृच्छिक मूल्य चुन रहे हैं, तो बहुत सरल कम-भ्रमित तरीका अक्षरों पर लूप होगा। यह विधि आपको पुनरावृत्ति से बचने की अनुमति देती है, क्या आपको सभी क्रमपरिवर्तन चाहिए, साथ ही यह आपको वैसा ही दिखता है जैसे आप मैथ्स (टीएम) जानते हैं !

यदि संयोजनों की संख्या अत्यधिक है, तो आप इसे छोटे शब्दों की एक श्रृंखला में तोड़ सकते हैं और अंत में उन्हें संक्षिप्त कर सकते हैं।


0

सी # पुनरावृत्त:

public List<string> Permutations(char[] chars)
    {
        List<string> words = new List<string>();
        words.Add(chars[0].ToString());
        for (int i = 1; i < chars.Length; ++i)
        {
            int currLen = words.Count;
            for (int j = 0; j < currLen; ++j)
            {
                var w = words[j];
                for (int k = 0; k <= w.Length; ++k)
                {
                    var nstr = w.Insert(k, chars[i].ToString());
                    if (k == 0)
                        words[j] = nstr;
                    else
                        words.Add(nstr);
                }
            }
        }
        return words;
    }

0
def gen( x,y,list): #to generate all strings inserting y at different positions
list = []
list.append( y+x )
for i in range( len(x) ):
    list.append( func(x,0,i) + y + func(x,i+1,len(x)-1) )
return list 

def func( x,i,j ): #returns x[i..j]
z = '' 
for i in range(i,j+1):
    z = z+x[i]
return z 

def perm( x , length , list ): #perm function
if length == 1 : # base case
    list.append( x[len(x)-1] )
    return list 
else:
    lists = perm( x , length-1 ,list )
    lists_temp = lists #temporarily storing the list 
    lists = []
    for i in range( len(lists_temp) ) :
        list_temp = gen(lists_temp[i],x[length-2],lists)
        lists += list_temp 
    return lists

0
def permutation(str)
  posibilities = []
  str.split('').each do |char|
    if posibilities.size == 0
      posibilities[0] = char.downcase
      posibilities[1] = char.upcase
    else
      posibilities_count = posibilities.length
      posibilities = posibilities + posibilities
      posibilities_count.times do |i|
        posibilities[i] += char.downcase
        posibilities[i+posibilities_count] += char.upcase
      end
    end
  end
  posibilities
end

यहाँ मेरा एक गैर पुनरावर्ती संस्करण पर ले रहा है



0

यहाँ एक सुंदर, गैर-पुनरावर्ती, ओ (एन!) समाधान है:

public static StringBuilder[] permutations(String s) {
        if (s.length() == 0)
            return null;
        int length = fact(s.length());
        StringBuilder[] sb = new StringBuilder[length];
        for (int i = 0; i < length; i++) {
            sb[i] = new StringBuilder();
        }
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            int times = length / (i + 1);
            for (int j = 0; j < times; j++) {
                for (int k = 0; k < length / times; k++) {
                    sb[j * length / times + k].insert(k, ch);
                }
            }
        }
        return sb;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.