【问题标题】:Compression of Integers整数压缩
【发布时间】:2015-08-07 19:14:06
【问题描述】:

如何将一排整数压缩成更短的整数?

例如输入:'1 2 4 9 8 5 2 7 6 2 3 4' -> 算法 -> 输出:'X Y Z'

可以反过来取回吗? ('X Y Z' -> '1 2 4 9 8 5 2 7 6 2 3 4')

输入最多包含 12 位数字,仅限数字。输出可以是字母数字,最多应为 3-4 位。

提前致谢。

编辑:每个输入数字0-9;输出0-9a-Z

【问题讨论】:

  • Input contains 12 digits max?所以输入将包含最多 12 个数字,或者输入中的每个数字最多有 12 个数字?
  • 这 12 个数字中是否存在任何(已知)系统?他们遵循一个模式吗?你能生成它们吗?它们是随机的吗?它们代表什么?
  • @PhamTrung 输入最多包含 12 位数字;每个数字 0-9
  • @LasseV.Karlsen 没有系统;没有意义;数字是随机的。
  • 那么阿米特已经发布了一个很好的答案:一般意义上是做不到的。压缩利用冗余或模式,如果两者都没有,则无法压缩。您可能碰巧有可以压缩的数据 some 但它会因数据集而异,而且您根本无法保证它会压缩到 3 甚至 11 个字节。这么说吧:如果你能找到一种方法,保证将非均匀随机数据从 12 个数字压缩到 3 个数字,注册一个专利,你就发财了!

标签: algorithm math integer compression


【解决方案1】:

类似的讨论 Compressing a set of large integers

PHP Compress array of bits into shortest string possible


$val = pack('H*', "124985276234");
echo '#'. $val . '#';
print_r(unpack('H*', $val));
die;

#Issue
00011001 => 25
11001    => 25

我试图在 PHP 中实现@Misch 算法,但是使用 decbin 时的一些位错误,并且在解包时给我带来了不好的结果。然后发现pack 函数和它的工作类似。但是解压时0到9的数字是错误的,在9000000测试8090899是解压值错误,没有发现碰撞。

set_time_limit(0);
ini_set('memory_limit', '5000M');
ini_set("max_execution_time",0);

$collision = [];
$err = [];
for ($i=0; $i < 9000000; $i++) { 

    $packed = pack('H*', $i);
    $unpacked = unpack('H*', $packed)[1];

    if ( array_key_exists($i, $collision) ) {
        die("Collision:". $i .' !!!!'. $packed .'!!!!'. $unpacked);
    }

    if ( $i != $unpacked ) {
        $e =  "Collision2:". $i .' !!!!'. $packed .'!!!!'. $unpacked . "\n";
        #echo $e;
        $err[] = $e;
    }
    $collision[] = $packed;

    #echo '#'. $i .'#' . $unpacked . '#' . $unpacked . "#\n";
}

【讨论】:

    【解决方案2】:

    首先,您可以通过某个库使用任何现有的压缩算法。但是知道您的输入非常专业,您也可以编写适合您的情况的特殊算法。

    但是让我们首先分析一下你可以压缩多少这个输入。为简化起见,我将首先考虑将 12 位数字从 0 压缩到 9(但是您没有明确写出输入范围是什么)。有 10^12 种可能的组合,比 2^40 少一点。所以你基本上想要做的是压缩 40 位。

    现在让我们分析一下如何压缩这 40 位。如果您将字母数字理解为[0-9A-Z],则可以使用 36 个字符。每个字符可以编码 log_2(36)=5.1 位。因此,对 40 位进行编码需要 8 个字母数字字符。

    更好的选择是使用 base64。在这里,您有 64 个字符,这意味着每个字符可以编码 6 位,因此您可以仅使用 40/6=6.666 => 7 个字符对输入进行编码。

    如果您考虑将输入压缩为二进制,您显然需要 40 位。这可以用 5 个 8 位 ASCII 字符、2 个 32 位整数或 1 个 64 位整数来编写。但是,这可能不是您想要实现的。

    结论:你不能任意压缩数据,你想压缩的数据也不能压缩到你想压缩的程度。


    例如,要将 0 到 9 的 12 位数字编码为 ASCII 字符,您可以简单地打印将它们转换为一个大数,将其转换为二进制,然后将该二进制数分成 8 位的部分并将它们转换为 ASCII人物。

    示例:

    Input: 1 2 4 9 8 5 2 7 6 2 3 4
    One number: 124985276234
    Binary: 1110100011001101100111111011101001010
    Grouped: 11101 00011001 10110011 11110111 01001010
    ASCII: <GS><EM>��J
    

    请注意,某些 ASCII 符号是不可打印的。如果这对您很重要,您将不得不使用另一种编码,例如 base 64,它只有 64 个不同的字符,但它们都是可打印的。

    【讨论】:

    • 5 个 8 位 ASCII 字符听起来也不错,你能大致解释一下如何做到这一点吗?
    • 添加了一种可能的编码算法,用于对您的数字进行 ASCII 编码
    【解决方案3】:

    除非您的输入来自特定域,否则许多输入是不可能/不可接受的 - 您不能这样做。

    您可以使用 4 个字母数字字符对 62^4~=1.4*10^7 不同的系列进行编码。
    另一方面,12 位数字的输入可以有 10^12 种可能的不同输入。

    来自pigeonhole principle - 必须有 2 个“压缩”映射到同一个输入。

    但是,由于您需要重新创建原始序列,因此您无法区分两个相同的压缩。

    所以这样的压缩是不存在的。

    事实上,要将一个 12 位数字压缩为 4 个字符,您将需要字母表来使字符大小为 1000:

    x^4 = 10^12, x>0
    x = 1000
    

    【讨论】:

    • 输出可以是字母数字,所以有 36^4 个不同的系列。不过,这仍然太小了。
    • 小写也一样? 62^4,但仍小于 64^4,即 16M。
    • @Hoopje 是的,在您发表评论前几分钟编辑并提到了它(并在几秒钟后添加了说明您需要多少个字符)。
    • 让我们接受一些具有> 1000个不同字符的字符集,那有可能吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多