Performance 根据定制订单获得第n个最小数字?
我试图解决这个问题:Performance 根据定制订单获得第n个最小数字?,performance,algorithm,math,bit-manipulation,Performance,Algorithm,Math,Bit Manipulation,我试图解决这个问题: 基本上,如果在x的二进制表示中1的数量大于y,则数字x大于y 如果它们有相同数量的1,那么我们会以自然的方式进行比较 现在我们有一个由整数1.组成的位序列。。2147483647。给定某个整数的索引,如何有效地得到该整数 注:序列中的前几个整数应为: 0, 1, 2, 4, 8, 16, 32, .. 1073741824, 3, 5, 6, 9, .. - --------------------------------- -------------- 0
x
的二进制表示中1
的数量大于y
,则数字x
大于y
1
,那么我们会以自然的方式进行比较1.组成的位序列。。2147483647
。给定某个整数的索引,如何有效地得到该整数
注:序列中的前几个整数应为:
0, 1, 2, 4, 8, 16, 32, .. 1073741824, 3, 5, 6, 9, ..
- --------------------------------- --------------
0 one 1's two 1's
注:
我想你可以把它分解成两个独立的问题:
function nthNumber(n):
let numBitsNeeded = 0;
while true:
let x = number of numbers with exactly numBitsNeeded bits.
if x >= n, break
n -= x
return the nth-smallest value with exactly numBitsNeeded bits
这个想法是计算数字n中有多少位,然后从那里确定需要多少位的数字
让我们分别讨论每个问题
第1部分:使用精确设置的k位计算值的数量
幸运的是,这部分有一个很好的闭式解决方案。如果您有一个32位数字,并且想知道有多少个数字正好设置了k位,那么您可以计算值32 choose k,因为您正在选择数字中哪些位置将设置该位。这可以计算为
32!/(k!(32-k)!)
如果您愿意,您可以预先计算这个值并将其放入表中,这意味着您可以在O(1)时间内计算这个值
第2部分:确定第n个最小数,并精确设置k位。
由于所有这些数字都有相同的位数,并且它们通常会进行比较,因此您可以将这部分问题视为查找k位的第n个按字典顺序排列的组合。你可以这样做的一种方法是:假设你知道有多少个数字的最高位在k,k+1,k+2,k+3等位置。然后你可以对这些数字进行二进制搜索,以确定数字的最高最佳位置。完成后,可以递归地应用相同的过程,但使用k-1位来恢复数字的剩余位
所以现在我们需要弄清楚如何计算选择k位的方法的数量,其中最高的1位在p的某个位置。幸运的是,这也没那么难。如果您有k位,并且最高值在位置p,那么您需要将剩余的k-1位分配到小于p的位置。方法的数量由(p-1)choose(k-1)给出,即
(p-1)!/(k-1)!((p-1)-(k-1))
结合上面的逻辑,您可以确定数字的所有位应该放在哪里,而不必一直向上计数
希望这有帮助 根据@templatetypedef的核心算法,我终于让它被接受了:
# Problem Verdict Language Run Time Submission Date
12534054 10232 Bit-wise Sequence Accepted C++ 0.018 2013-10-21 00:39:12
积分应该仍然归@templatetypedef,但我也发布了主代码供其他人参考
代码实际上很短,因为大部分是我的注释:-)
主要代码(我花了很多时间解决“偏移量1”问题):
测试输出:
0
1
2
1073741824
3
0
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
3
5
1610612736
7
11
2147483647
1195924317
1467508257
147227152
1099186184
135856144
1247429124
57624
100730919
嗯,第二部分听起来有点复杂,但我会试试。顺便说一句,它是
31
,而不是32
。为了加快速度,我还将在一个查找表中预计算第二部分的一部分,因为只有31*31个案例。@PeterLee templatetypedef已经很好地解释了这一点,但是可视化可能会有所帮助。您可以将其视为一种“bucketing”算法,在该算法中,您将初始的一组数字拆分为多个存储桶。然后你找到你的号码所在的桶。。。然后把桶分成更小的桶。继续执行此操作,直到桶的大小为0或1,此时。。。你有你的目标号码。@roliu,是的,这就是我在评论中的意思。Thx:-)
0
1
2
31
32
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
496
497
498
2147483647
1234567890
987654321
6123512
852412
123125
67658153
214155
5623674
0
1
2
1073741824
3
0
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
3
5
1610612736
7
11
2147483647
1195924317
1467508257
147227152
1099186184
135856144
1247429124
57624
100730919