Finding the ranking of a word (permutations) with duplicate letters

前端 未结 6 622
有刺的猬
有刺的猬 2020-11-27 07:09

I\'m posting this although much has already been posted about this question. I didn\'t want to post as an answer since it\'s not working. The answer to this post (Finding th

6条回答
  •  轮回少年
    2020-11-27 07:34

    Note: this answer is for 1-based rankings, as specified implicitly by example. Here's some Python that works at least for the two examples provided. The key fact is that suffixperms * ctr[y] // ctr[x] is the number of permutations whose first letter is y of the length-(i + 1) suffix of perm.

    from collections import Counter
    
    def rankperm(perm):
        rank = 1
        suffixperms = 1
        ctr = Counter()
        for i in range(len(perm)):
            x = perm[((len(perm) - 1) - i)]
            ctr[x] += 1
            for y in ctr:
                if (y < x):
                    rank += ((suffixperms * ctr[y]) // ctr[x])
            suffixperms = ((suffixperms * (i + 1)) // ctr[x])
        return rank
    print(rankperm('QUESTION'))
    print(rankperm('BOOKKEEPER'))
    

    Java version:

    public static long rankPerm(String perm) {
        long rank = 1;
        long suffixPermCount = 1;
        java.util.Map charCounts =
            new java.util.HashMap();
        for (int i = perm.length() - 1; i > -1; i--) {
            char x = perm.charAt(i);
            int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
            charCounts.put(x, xCount);
            for (java.util.Map.Entry e : charCounts.entrySet()) {
                if (e.getKey() < x) {
                    rank += suffixPermCount * e.getValue() / xCount;
                }
            }
            suffixPermCount *= perm.length() - i;
            suffixPermCount /= xCount;
        }
        return rank;
    }
    

    Unranking permutations:

    from collections import Counter
    
    def unrankperm(letters, rank):
        ctr = Counter()
        permcount = 1
        for i in range(len(letters)):
            x = letters[i]
            ctr[x] += 1
            permcount = (permcount * (i + 1)) // ctr[x]
        # ctr is the histogram of letters
        # permcount is the number of distinct perms of letters
        perm = []
        for i in range(len(letters)):
            for x in sorted(ctr.keys()):
                # suffixcount is the number of distinct perms that begin with x
                suffixcount = permcount * ctr[x] // (len(letters) - i)
                if rank <= suffixcount:
                    perm.append(x)
                    permcount = suffixcount
                    ctr[x] -= 1
                    if ctr[x] == 0:
                        del ctr[x]
                    break
                rank -= suffixcount
        return ''.join(perm)
    

提交回复
热议问题