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

Algorithm 使用尽可能小的基数表示d位数上的整数,algorithm,sorting,base,Algorithm,Sorting,Base,我想创建一个函数,其中对于任意整数输入值(比如无符号32位)和给定数量的d数字,返回值将是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

我想创建一个函数,其中对于任意整数输入值(比如无符号32位)和给定数量的
d
数字,返回值将是
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,每个输入值应有一个唯一的输出值。想象一下,函数应该从奇怪排序的
B
基数列表中返回
n

实际上,这是迄今为止我能想到的唯一方法——给定一个输入值,以尽可能最小的
B
基生成所有数字,以表示
d
数字上的输入,然后对结果应用自定义排序(“惩罚”较高的数字值,并将其放回排序中),并返回排序数组中的第n个值。这会起作用,但这是一个效率极低的实现——我希望在不生成输入值之前的所有数字的情况下完成这项工作


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

假设所有值都是正数,让我们进行简单的数学计算:
基于d位B的数字可以保存值N,如果

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
德尔菲代码

  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为基数(例如,对于最大基数为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与以3为基数的9个2位数组合起来

当第一个数字小于组中的最大数字时,我们可以将其与基3的9个2位数字组合,但我们不能使用与基2的4个2位数字不明确的4个2位数字。这给了我们数字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示例。表示形式将作为数字列表返回,因此您可以表示2^32− 1作为[307129090]

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
导入数学
def代表(x、ndigit、基本):
“”“给定基中x的直接表示”“”
s=[]
而ndigit:
s+=[x%基准]
x/=基准
ndigit-=1
返回s
def编码(x,ndigit):
“”“根据最小基数编码,固定数字顺序”“”

如果ndigit我不理解数字>=8的输出,你能解释一下吗?@Henry Base 2转到
2^3-1
,Base 3转到
3^3-1
,Base 4转到
4^3-1
,等等。十进制8不能用二进制的3位数字表示,所以8应该对应于第一个不是有效二进制的三元数,那么检查d位数的基数B中可能的最大数呢。你可以在基B上应用二进制搜索。预计的时间复杂度是多少?@coderredoc我希望有一种解决方案不涉及搜索或排序,而只涉及巧妙的赋值。如果不是这样的话,O(n)就好了。这给了我最小的B基数,给定的输入值可以用d数字表示,但没有给我一个与输入值对应的唯一的B基数。最后的输出,使用你的例子,应该是2位数字,以10、11、8和6为基数,如“99”、“0A”等。数字可以通过整数除以基数(并转换为正确的符号)来计算。这正是我想要的,我需要测试一下,然后返回给你。我的例子中的顺序是任意的,对我来说唯一重要的约束是二进制数应该在四元数之前的三元数之前,等等。你的解决方案似乎非常适合这个。太棒了!工作正常!++非常感谢,非常聪明和高效的解决方案。