Calculate the index of a given number within a sorted set

谁都会走 提交于 2019-12-19 10:04:03

问题


Not sure if this question should be on Math-Overflow or here, so will try here first:

Suppose we are given a number with N 1s and M 0s.

There are (M+N)!/(M!*N!) different such numbers, that can be sorted in a countable set.

For example, the sorted set of all numbers with 2 ones and 3 zeros, is:

  • 0 00011
  • 1 00101
  • 2 00110
  • 3 01001
  • 4 01010
  • 5 01100
  • 6 10001
  • 7 10010
  • 8 10100
  • 9 11000

How can we efficiently calculate the index of a given number within the corresponding set?

Note: the input to this question is only the number, and not the entire (corresponding) set.


回答1:


Let choose (n, k) = n! / k! / (n-k)!.

Observe the following structure of your sorted set:

0 0|0011 1 0|0101 2 0|0110 3 0|1001 4 0|1010 5 0|1100 ------ 6 1|0001 7 1|0010 8 1|0100 9 1|1000

In the sorted set, there are choose (N + M, M) numbers (binary strings of length N + M) in total. First go the numbers starting by a zero, and there are choose (N + M-1, M-1) of them. Then go the numbers starting by a one, and there are choose (N-1 + M, M) of them. Each of these two sections is also sorted.

So, if your number b1b2...bk starts with a zero (b1 = 0), its index in the sorted set is the same as index of b2...bk in the sorted set of all binary strings of N ones and M-1 zeroes. If it starts with a one (b1 = 1), its index in the sorted set is the same as index of b2...bk in the sorted set of all binary strings of N-1 ones and M zeroes, plus the total number of binary strings starting with a zero, which is choose (N + M-1, M-1).

In this way, you recursively descent to subproblems involving suffixes of your original binary string, increasing the sought number by some amount whenever you meet a 1. In the end, you come to an empty binary string which clearly is the one and only string consisting of 0 zeroes and 0 ones.




回答2:


This is called ranking in combinatorial algorithms. Here is a C function that does that for you:

unsigned long rank_choose(unsigned long n, unsigned long k, unsigned long c) {
  unsigned long res = 0;
  for (; n > 0; n--) {
    if (c & 1) { res += binomial(n-1, k); k--;}
    c >>= 1;
  }
  return res;
}

It assume that you have a function binomial(n, k) which compute the coefficient n!/k!/(n-k)!. Be careful, the solution I propose here use an endianess reversed representation:

const int m = 5, n = 2;
int k = 12;
std::cout << std::bitset<m>(k) << " " << rank_choose(m, n, k) << std::endl;
k = 9;
std::cout << std::bitset<m>(k) << " " << rank_choose(m, n, k) << std::endl;

Returns:

01100 2
01001 7

Here is a solution with the other endianess:

unsigned long rank_choose_rev(unsigned long n, unsigned long k, unsigned long c) {
  unsigned long res = 0, mask = 1<<(n-1);
  for (; n > 0; n--) {
    if (c & mask) { res += binomial(n-1, k); k--;}
    mask >>= 1;
  }
  return res;
}

Then

01100 5
01001 3

Note : The algorithms is nicely described by @Gassa below (+1 to him).




回答3:


I'll explain one solution with the help of an example. Say there are 3 ones and 3 zeroes and we have to find the index of 010110

The first one from left is at the second position. Hence all number that have double zeroes at their right shall be less than this number:

00---- (C(4,3)) = 4

Now place this one at its position and move to the next one. Next one is at position 4. Hence all the following numbers shall be less than the candidate:

0100-- (C(2,2)) = 1

Now place this one at its position and move to the next one. Next one is at position 5. Hence all the following numbers shall be less than the candidate:

01010- (C(1,1)) = 1

Hence the number of numbers less than the candidate = 4 + 1 + 1 = 6

000111
001011
001101
001110
010011
010101
010110


来源:https://stackoverflow.com/questions/22219074/calculate-the-index-of-a-given-number-within-a-sorted-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!