它可以通过组合和排列技术来解决。
F(N) = 等级
首先找到表示 N 所需的位数。在二进制表示中,数字可以构造如下:
N = cn 2^n + .... + c3 2^2 + c2 2^1 + c1 2^0
现在,为了n
在上述等式中找到(或数字的二进制表示中的位数),我们可以假设它将是floor(log2(N)) + 1
。例如,考虑任何数字,假设118
它可以用 floor(log2(118)) + 1 = 7 位表示。
n = floor(log2(118)) + 1;
上式只有O(1)
. 现在,我们需要找出一个数字的二进制表示中有多少个 1。考虑一个伪代码来完成这项工作:
function count1(int N) {
int c = 0;
int N' = N;
while(N' > 0) {
N' -= 2^(floor(log2(N')));
c++;
}
}
上面的伪代码是O(logN)
. 我在 MATLAB 中编写了小脚本来测试我上面的伪代码,结果如下。
count1(6) = 2
count1(3) = 2
count1(118) = 5
完美,现在我们有了这些位的位数和 1 的数量。现在,可以应用简单的组合和排列来找到数字的秩。首先让我们假设,n
是表示数字所需的位数,并且c
是数字的位表示中的 1 的数量。因此,排名将由以下方式给出:
r = n ! / c ! * (n - c) !
编辑:正如 DSM 所建议的,我已经更正了逻辑以找到正确的 RANK。想法是从排列中删除所有不需要的数字。所以添加了这段代码:
for i = N + 1 : 2^n - 1
if count(i) == c
r = r - 1;
end
end
我编写了一个 MATLAb 脚本来使用上述方法查找数字的等级:
function r = rankN(N)
n = floor(log2(N)) + 1;
c = count(N);
r = factorial(n) / (factorial(c) * factorial(n - c));
% rejecting all the numbers may have included in the permutations
% but are unnecessary.
for i = N + 1 : 2^n - 1
if count(i) == c
r = r - 1;
end
end
function c = count(n)
c = 0;
N = n;
while N > 0
N = N - 2^(floor(log2(N)));
c = c + 1;
end
上面的算法是O(1) + O(logN) + O(1) = O(logN)
。输出是:
>> rankN(3)
ans =
1
>> rankN(4)
ans =
3
>> rankN(7)
ans =
1
>> rankN(118)
ans =
18
>> rankN(6)
ans =
3
注意:排名0
始终是1
因为上述方法将失败,0
因为log2(0)
未定义。