making unique combinations from the given characters

前端 未结 2 934
谎友^
谎友^ 2021-01-15 04:01

Is there any algorithm available for this one :

From a group of characters like :

a,@,n,M,O,f,D,),`,~,;,N,*,8,2,],2........ goes one . There are abou         


        
相关标签:
2条回答
  • 2021-01-15 04:33

    UPDATE: Here is a working python version of combinations without repetitions:

    def ncombs(n,k):
        if n < 0 or k < 0 or k > n: return 0
        b = 1
        for i in xrange(k): b = b*(n-i)/(i+1)
        return b
    
    def nthresh(k, idx):
        """Finds the largest value m such that C(m, k) <= idx."""
        mk = k
        while ncombs(mk, k) <= idx:
            mk += 1
        return mk - 1
    
    def rank_to_comb(k, rank):
        ret = []
        for i in range(k, 0, -1):
            element = nthresh(i, rank)
            ret.insert(0, element)
            rank -= ncombs(element, i)
        return ret
    
    def random_combination(choices, n):
        num_combinations = ncombs(len(choices), n)
        desired_rank = random.randint(0, num_combinations-1)
        indices = idx_to_set(n, desired_rank)
        return [choices[i] for i in indices]
    

    Sample usage:

    >>> random_combination("abcdefghijkl", 3)
    ['b', 'd', 'h']
    >>> random_combination("abcdefghijkl", 3)
    ['b', 'd', 'g']
    >>> random_combination("abcdefghijkl", 3)
    ['d', 'f', 'i']
    >>> random_combination("abcdefghijkl", 3)
    ['d', 'f', 'h']
    >>> random_combination("abcdefghijkl", 3)
    ['b', 'c', 'e']
    >>> random_combination("abcdefghijkl", 3)
    ['c', 'i', 'l']
    >>> random_combination("abcdefghijkl", 3)
    ['c', 'g', 'j']
    >>> random_combination("abcdefghijkl", 3)
    ['b', 'j', 'l']
    

    It works by generating the rank of the desired combination, then generating the combination from the rank, then using that to index into the list of choices. By doing so you guarantee an even distribution of indices (so you don't generate any one combination more often than others).

    For example, if you wanted to choose 5 elements from a list of 10, there are 10 C 5 = 252 possible combinations. The first combination is (0, 1, 2, 3, 4), the second is (0, 1, 2, 3, 5), the third is (0, 1, 2, 4, 5), etc... The rank_to_comb function accomplishes the translation:

    >>> rank_to_comb(5, 0)
    [0, 1, 2, 3, 4]
    >>> rank_to_comb(5, 1)
    [0, 1, 2, 3, 5]
    >>> rank_to_comb(5, 2)
    [0, 1, 2, 4, 5]
    >>> rank_to_comb(5, 250)
    [4, 6, 7, 8, 9]
    >>> rank_to_comb(5, 251)
    [5, 6, 7, 8, 9]
    

    So we just uniformly pick a number from 0 to 251, get the combination, index into the choices list, and we're done!


    This is the old version that generated permutations, not combinations:

    Here is how to generate one combination:

    public static String comboFrom(String possibleChars, int charsToTake) {
        //randomly shuffle the chars using Collections.shuffle
        List<Character> chars = new ArrayList<Character>(possibleChars.length());
        for (char c : possibleChars.toCharArray()) {
            chars.add(new Character(c));
        }
    
        Collections.shuffle(chars);
    
        //Take the first 'charsToTake' characters - these will be totally random
        //thanks to the shuffle
        String result = ""; 
        int taken=0;
        for (Character c : chars) {
            result += c.charValue();
            if (taken >= charsToTake) break;
            taken += 1;
        }
        return result;
    }
    

    Sample usage:

    for (int i=0; i < 30; i++) {
        System.out.println(comboFrom("abcdefghijkl@#%", 5));
    }
    

    Resulted in:

    ecjlaf
    bi@hfj
    ia@#e%
    icfad@
    kb#gei
    ik%@de
    ib%jkf
    flgb@#
    gd@ekc
    jedhi#
    f@%ckj
    lig%#j
    l%fki#
    ajgdlc
    adkbe@
    gb@cid
    #efcag
    @lihkc
    k@j%#c
    cgkaji
    ecb@hj
    k@lf%a
    gd%fbh
    c%lajf
    e@#cid
    %gfeb#
    #%ahcf
    be@flj
    albjk@
    calh%g
    

    You can just call this function repeatedly and stop when you get a result that satisfies your needs. Here is the full code I used.

    EDIT: And sorry for this plug but this was so much more annoying to do than I thought that I'm glad I'm using Python at my job:

    import random
    def comboFrom(possibleChars, charsToTake):
        chars = list(possibleChars)
        random.shuffle(chars)
        return "".join(chars[:charsToTake])
    
    0 讨论(0)
  • 2021-01-15 04:42

    First be aware that the number of possible permutations is in O(n^k) (Choose(n,k) = n!/(k!*(n-k)!) to be exact) where n is the number of characters and k is the desired length. Since it is exponential it could easily grow out of reach.

    A general algorithm for achieving these combinations is using recursion and explore all possibilites up to this length. At each level you "guess" which character you will use next, place it, remove it from the list of available chars and recurse to solve the smaller problem (finding permutation up to length-1).

    private static void printPermutations(char[] chars, int idx, List<Character> candidate, int length) {
        if (length == candidate.size()) { 
            System.out.println(candidate);
            return;
        }
        for (int i = idx; i < chars.length; i++) {
            candidate.add(chars[i]);
            //set the selected element out of reach:
            char temp = chars[idx];
            chars[idx] = chars[i];
            chars[i] = temp;
            //recurse:
            printPermutations(chars, idx+1, candidate, length);
            //clean up environment:
            temp = chars[i];
            chars[i] = chars[idx];
            chars[idx]  = temp;
            candidate.remove(candidate.size()-1);
        }
    }
    public static void printPermutations(char[] chars, int length) { 
        printPermutations(chars, 0, new LinkedList<Character>(), length);
    }
    
    0 讨论(0)
提交回复
热议问题