使用最小的可能基数表示 d 位上的整数

Represent integers on d digits using smallest possible base

我想创建一个函数,其中对于任意整数输入值(比如无符号 32 位)和给定的 d 位数,return 值将是 d 数字 B 基数,B 是可用于表示 d 数字上给定输入的最小基数。

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

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
    ..      .....

赋值应该是1:1,对于每个输入值,应该只有一个唯一的输出值。把它想象成函数应该 return 来自奇怪排序的 B 基数列表的 nth 值。

实际上,这是迄今为止我能想到的唯一方法 - 给定一个输入值,以尽可能小的 B 为基数生成所有数字,以表示 d 数字上的输入,然后对结果应用自定义排序('penalizing' 较高的数字值并将它们放在排序的后面),以及 return 来自已排序数组的 nth 值。这会起作用,但这是一个非常低效的实现 - 我想在不生成输入值的所有数字的情况下执行此操作。

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

假设所有值都是正数,让我们做一个简单的数学运算:
d-digit B-based number 可以容纳值 N if

Bd > N

所以

B > N1/d

所以计算N1/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]

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

我不太确定您示例中的顺序。我的答案是基于不同的顺序:创建所有可能的 n 位数字,直到基数 b(例如,所有数字最多为 999 的最大值。基数 10 和 3 位数字)。首先根据最大数字对它们进行排序。数字在具有相同最大数字的组内正常排序。这保留了从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

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

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

当第一个数字小于组中的最大数字时,我们可以将其与9个3进制的2位数字组合,但不能使用与组中有歧义的4个2位数字4 以 2 为基数的 2 位数字。这为数字 0 和 1 提供了五种可能性。这些可能性 - 02、12、20、21 和 22 - 可以描述为根据相同方案的两位数的唯一数字,但有一个偏移量:

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

这导致递归解决方案:

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

这是 Python 中的示例。表示形式是 returned 作为数字列表,因此您可以将 2^32 − 1 表示为 [307, 1290, 990]。

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