【问题标题】:Creating hash function to map 6 numbers to a short string创建哈希函数以将 6 个数字映射到一个短字符串
【发布时间】:2018-06-19 04:48:18
【问题描述】:

我有 6 个变量 0 ≤ n₁,...,n₆ ≤ 12,我想构建一个哈希函数来执行直接映射 D(n₁,n₂,n₃,n₄,n₅,n₆) = S 和另一个函数来执行逆映射 I(S) = (n₁,n₂,n₃,n₄,n₅,n₆),其中 S 是一个字符串(az、AZ、 0-9)。

我的目标是将 S 的长度最小化为 3 或更少。

我以为变量有13个可能的值,一个字母(az)应该可以代表其中的2个,但我意识到1 + 12 = m2 + 11 = m,所以我还是不知道怎么写一个函数。

有没有什么方法可以构建一个函数来完成这个映射并返回一个小字符串?

如果有必要,可以选择使用整个 ASCII 来表示 S。

【问题讨论】:

  • 你能举个例子,比如 6 个数字的输入和它们的哈希 = $56 ...但我的问题是总是有 6 个数字存在吗?
  • 12^6=144^3 > 125^3,你不能。也许我错了。
  • @zenwraight 你是对的,D(1,2,3,4,5,6) = X8% 可能
  • @Silencer 你能解释一下你是怎么想出这些数字的吗?
  • 12^6(实际上我认为他的意思是 13^6)是输入变量的可能性数量,125^3 意味着不可能用 ASCII 的 125 个字符来表示这些可能性3 个字符

标签: algorithm hash mapping


【解决方案1】:

我认为变量有 13 个可能的值,一个字母 (a-z) 应该能够代表其中的 2 个

这个推理是错误的。事实上,要表示两个变量(=这些变量可能采用的任何组合),您将需要 13x13 = 169 个符号。

对于您的示例,6 个变量可以采用 13^6 (=4826809) 种不同的组合。为了表示所有可能的组合,您需要 5 个字母 (a-z),因为 26^5 (=11881376) 是产生超过 13^6 个组合的最少数量。

对于 ASCII 字符,3 个符号就足够了,因为 256^3 > 13^6。

如果您仍然对进行转换的代码感兴趣,我很乐意为您提供帮助。

【讨论】:

  • 取决于您如何定义 ASCII。最初的 ASCII 是 7 位的,只产生 128 个可能的字符。考虑到大约 30 个左右是不可打印的,因此您可以使用的只有不到 100 个。
【解决方案2】:

您可以使用基本转换将任何给定范围内的一组数字转换为任何其他范围内的数字。

二进制是基数 2 (0-1),十进制是基数 10 (0-9)。你的 6 个数字是以 13 为底 (0-12)。

检查是否可能进行转换涉及计算每个集合的可能值组合的数量。对于 [0,n] 范围内的每个数字(因此以 n+1 为底),我们可以从所有 0 到所有 n,因此每个数字可以取 n+1 个值,并且可能性的总数是 (n+1 )numberCount。例如,对于 6 位十进制数字,它会是 106 = 1000000,这可以通过,因为有 1000000 个可能的数字(最多)6 位,即数字

大小写字母和数字 (26+26+10) 将以 62 (0-61) 为基数,但根据上述情况,3 个这样的值不足以表示您的 6 个数字 (13 6 > 623)。要从/到这些转换,您可以转换为一组以 62 为基数的数字,然后使用适当的 if 语句来转换 0-9 0-9、az 10-35、AZ 36-61。

您可以用 3 个字节表示您的数据(因为 2563 >= 136),尽管这不一定是可打印字符 - 考虑 32-126标准可打印范围(仍然太小),128-255 是扩展范围,可能无法在任何给定环境中正确显示(为了获得正确显示的最佳机会,您至少应该避免 0- 31 和 127,它们是控制字符 - 您可以将 0-... 转换为上述范围,方法是添加 32,然后如果值 >= 127,则添加另一个 1)。

许多/大多数语言应该允许您提供一个数值来表示一个字符,因此一旦您进行基本转换,输出它应该相当简单。虽然有些人可能会使用 Unicode 来表示字符,但这可能会使使用 ASCII 变得不那么简单。

如果数字有特定限制,这将减少可能组合的数量,从而可能使其适合更小的数字集合或范围。

做实际的基础转换:

首先将其转换为常规整数类型(通常是二进制或十进制)可能是最简单的,我们不必担心基数,然后将其转换为目标基数(尽管首先确保您的值将适合您使用的任何数据类型)。

考虑二进制的工作原理:

1101 is 13 = 23 + 22 + 20

13 % 2 = 1   13 / 2 = 6
6  % 2 = 0    6 / 2 = 3
3  % 2 = 1    3 / 2 = 1
1  % 2 = 1
The above, from top to bottom: 1101 = our number

使用相同的想法,我们可以转换为/从任何基数如下:(伪代码)

int convertFromBase(array, base):
   output = 0
   for each i in array
      output = base*output + i
   return output

int[] convertToBase(num, base):
   output = []
   while num > 0
      output.append(num % base)
      num /= base
   output.reverse()
   return output

您还可以将此逻辑扩展到每个数字在不同范围内的情况,方法是更改​​您在每个步骤中的除数或倍数(对此的详细解释可能有点超出问题的范围)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2012-08-05
    • 2013-11-20
    • 1970-01-01
    • 2016-01-10
    • 2016-07-06
    相关资源
    最近更新 更多