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
    
    注:

  • 创建查找表是可行的,但速度太慢,内存太多
  • 将所有整数分配到具有不同数字1的包中也非常慢:如何在同一个包中计数,我必须逐个计数吗
  • 我不是学生。我是一名专业工作人员。解决ACM问题只是我的爱好。如果我相信有更有效的算法,使用暴力通常不是我的爱好

  • 我想你可以把它分解成两个独立的问题:

  • 查找设置了k位的数字数量,以及
  • 查找第n个最小数,且设置了精确的k位
  • 假设你能解决问题(1)和(2)。然后,这里有一个解决整个问题的方案,用可怕的伪代码编写:

    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