Compute rank of a combination?

前端 未结 7 1392
灰色年华
灰色年华 2020-11-30 06:07

I want to pre-compute some values for each combination in a set of combinations. For example, when choosing 3 numbers from 0 to 12, I\'ll compute some value for each one:

7条回答
  •  醉酒成梦
    2020-11-30 06:44

    Here is a conceptual answer and a code based on how lex ordering works. (So I guess my answer is like that of "moron", except that I think that he has too few details and his links have too many.) I wrote a function unchoose(n,S) for you that works assuming that S is an ordered list subset of range(n). The idea: Either S contains 0 or it does not. If it does, remove 0 and compute the index for the remaining subset. If it does not, then it comes after the binomial(n-1,k-1) subsets that do contain 0.

    def binomial(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 unchoose(n,S):
        k = len(S)
        if k == 0 or k == n: return 0
        j = S[0]
        if k == 1: return j
        S = [x-1 for x in S]
        if not j: return unchoose(n-1,S[1:])
        return binomial(n-1,k-1)+unchoose(n-1,S)
    
    def choose(X,k):
        n = len(X)
        if k < 0 or k > n: return []
        if not k: return [[]]
        if k == n: return [X]
        return [X[:1] + S for S in choose(X[1:],k-1)] + choose(X[1:],k)
    
    (n,k) = (13,3)
    for S in choose(range(n),k): print unchoose(n,S),S
    

    Now, it is also true that you can cache or hash values of both functions, binomial and unchoose. And what's nice about this is that you can compromise between precomputing everything and precomputing nothing. For instance you can precompute only for len(S) <= 3.

    You can also optimize unchoose so that it adds the binomial coefficients with a loop if S[0] > 0, instead of decrementing and using tail recursion.

提交回复
热议问题