使用尽可能小的基数

时间:2016-01-11 07:34:38

标签: algorithm sorting base

我想创建一个函数,其中对于任意整数输入值(让我们说无符号32位)和给定数量的d数字,返回值将是{{ 1}}数字d基数,B是可用于表示B数字上给定输入的最小基数。

这是一个示例输入 - 输出我想到的3位数字:

d

赋值应为1:1,对于每个输入值,应该只有一个唯一的输出值。可以把它想象成函数应该从奇怪排序的Input Output 0 0 0 0 1 0 0 1 2 0 1 0 3 0 1 1 4 1 0 0 5 1 0 1 6 1 1 0 7 1 1 1 8 0 0 2 9 0 1 2 10 1 0 2 11 1 1 2 12 0 2 0 13 0 2 1 14 1 2 0 15 1 2 1 16 2 0 0 17 2 0 1 18 2 1 0 19 2 1 1 20 0 2 2 21 1 2 2 22 2 0 2 23 2 1 2 24 2 2 0 25 2 2 1 26 2 2 2 27 0 0 3 28 0 1 3 29 1 0 3 30 1 1 3 .. ..... 基数列表中返回nth值。

实际上这是我到目前为止唯一的方法 - 给定输入值,在尽可能小的B基数中生成所有数字以表示B位数的输入,然后应用对结果进行自定义排序('惩罚'更高的数字值并将它们放回排序中),并从排序的数组中返回d值。这可行,但实现效率极低 - 我希望在不生成输入值的所有数字的情况下执行此操作。

实现此功能的有效方法是什么?任何语言或伪代码都可以。

2 个答案:

答案 0 :(得分:2)

假设所有值都是正数,那么让我们进行简单的数学计算:
如果

,d位基于B的数字可以保持值N.

B d > Ñ

所以

B> N 1 / d

因此,计算N 1 / d 值,将其四舍五入(如果为整数则递增),您将获得最小的基数B. (请注意,可能会出现数字错误)

示例:

d=2, N=99 => 9.95 => B=10
d=2, N=100 => 10  => B=11
d=2, N=57 => 7.55 => B=8
d=2, N=33 => 5.74 => B=6

Delphi代码

  function GetInSmallestBase(N, d: UInt32): string;
  const
    Digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  var
    Base, i: Byte;
  begin
    Base := Ceil(Power(N, 1/d) + 1.0E-12);
    if Base > 36 then
      Exit('Big number, few digits...');
    SetLength(Result, d);
    for i := d downto 1 do begin
      Result[i] := Digits[1 + N mod Base]; //Delphi string is 1-based
      N := N div Base;
    end;
    Result := Result + Format(' : base [%d]', [Base]);
  end;

begin
  Memo1.Lines.Add(GetInSmallestBase(99, 2));
  Memo1.Lines.Add(GetInSmallestBase(100, 2));
  Memo1.Lines.Add(GetInSmallestBase(987, 2));
  Memo1.Lines.Add(GetInSmallestBase(1987, 2));
  Memo1.Lines.Add(GetInSmallestBase(87654321, 6));
  Memo1.Lines.Add(GetInSmallestBase(57, 2));
  Memo1.Lines.Add(GetInSmallestBase(33, 2));

99 : base [10]
91 : base [11]
UR : base [32]
Big number, few digits...
H03LL7 : base [22]
71 : base [8]
53 : base [6]

答案 1 :(得分:2)

MBo的答案显示了如何找到代表具有给定位数的整数的最小基数。

我不太确定你的例子中的顺序。我的答案基于不同的排序:创建所有可能的 n - 数字,最多为基数 b (例如,最大基数为10和3位的所有数字最多为999) 。首先根据最大数字对它们进行排序。数字是在具有相同最大数字的组内的正常范围内排序的。这保留了从8到26的所有值必须为3的基本特征,但内部排序不同:

  8      0 0 2
  9      0 1 2
 10      0 2 0
 11      0 2 1
 12      0 2 2
 13      1 0 2
 14      1 1 2
 15      1 2 0
 16      1 2 1
 17      1 2 2
 18      2 0 0
 19      2 0 1
 20      2 0 2
 21      2 1 0
 22      2 1 1
 23      2 1 2
 24      2 2 0
 25      2 2 1
 26      2 2 2

当你的基数为2时,生活很简单:只需生成适当的二进制数。

对于其他基础,让我们看一下第一个数字。在上面的示例中,五个数字以0开头,五个以1开头,九个以2开头。当第一个数字为2时,最大数字保证为2.因此,我们可以将2与9个2位数字组合基地3。

当第一个数字小于组中的最大数字时,我们可以将它与基数3的9个2位数字组合,但我们不能使用与4 2不明确的4个2位数字。 -digit number of base 2.这给了我们5个数字0和1的可能性。这些可能性 - 02,12,20,21和22 - 可以描述为具有两个数字的唯一数字,根据相同的方案,但是抵消:

 4     0 2
 5     1 2
 6     2 0
 7     2 1
 8     2 2

这导致递归解决方案:

  • 一位数,只需返回数字;
  • 对于基数为2,返回基数为2的简单表示;
  • 如果第一个数字是确定的基数的最大数字,则将其与该基数中的直接表示相结合;
  • 否则将其与递归确定的相同算法的表示相结合,只需少一个数字。

这是Python中的一个例子。该表示作为数字列表返回,因此您可以将[^,3290,990]表示为2 ^ 32 - 。

import math

def repres(x, ndigit, base):
    """Straightforward representation of x in given base"""

    s = []

    while ndigit:
        s += [x % base]
        x /= base
        ndigit -= 1

    return s



def encode(x, ndigit):
    """Encode according to min-base, fixed-digit order"""

    if ndigit <= 1:
        return [x]

    base = int(x ** (1.0 / ndigit)) + 1

    if base <= 2:
        return repres(x, ndigit, 2)

    x0 = (base - 1) ** ndigit
    nprev = (base - 1) ** (ndigit - 1)
    ncurr = base ** (ndigit - 1)
    ndiff = ncurr - nprev

    area = (x - x0) / ndiff

    if area < base - 1:
        xx = x0 / (base - 1) + x - x0 - area * ndiff
        return [area] + encode(xx, ndigit - 1)

    xx0 = x0 + (base - 1) * ndiff
    return [base - 1] + repres(x - xx0, ndigit - 1, base)



for x in range(32):
    r = encode(x, 3)
    print x, r