如何压缩字符串

3

我在一次面试中遇到了这个问题:

给定一个字符串,如何压缩它?

输入示例不是以 aabbccdd 的形式出现,而是像 abcdgehrk。即 string 中的所有 chars 都不同。(注意:无法使用运行长度编码(Run Length Encoding),因为它是我给出的解决方案之一,但他说字符串没有重复的字符)

我提供了以下两个解决方案,但他们都没有被接受:

1)HashCode 不能作为解决方案,因为它将存储数字
2)无法以二进制形式存储,因为它不是人类可读的格式

请问有谁能提供另一个解决这个问题的方案吗?


1
有一种著名的压缩技术,叫做Huffman编码。你所说的二进制存储是什么意思?在内存中,所有东西都以二进制形式存储。 - Pham Trung
1
现在有一个问题,他希望它以人类可读的格式呈现。因此,霍夫曼编码不起作用。哈希也是我给出的答案之一。看起来面试官本身并不确定他在问什么,或者对压缩没有意识。 - arpit joshi
3个回答

4
考虑到考官要求压缩字符串易于阅读,其中一个解决方案是Run-Length Encoding

因此,aabbccdd将被压缩为2a2b2c2d,abcdgehrk将被压缩为1a1b1c1d1g1e1h1r1k。

请注意,在这些特殊的示例中,输出字符串并不比原始字符串更短,但所有无损压缩算法都具有的一个特点是,它们无法保证对任何输入数据集进行压缩。


是的,我曾向考官问过同样的问题,aabbccdd 是一个简单的任务,但就像如何压缩字符串 abcd 一样。我提供了相同的行程长度编码解决方案,但他说不行。 - arpit joshi
像 abcdgehrk 或 abcd 这样的字符串,根据要求是不可压缩的 -- 它们由所有不同的符号组成。 - dr_
1
是的,完全正确,这就是我想的。但由于那是一家大公司,我认为面试官不会那么愚蠢,但在通过谷歌之后,我发现确实很愚蠢。 - arpit joshi

1
如果要求字符串只由小写字母组成,每个字符可以用5位表示(2^5 = 32种可能的字符)。一个8个字符的字符串可以用40位(5字节)表示。
以下是将3个字符放入2个字节的示例:
a = 00001
b = 00010
c = 00011

字符串 "cab" 可以适合于:

  c     a     b   (extra bit)
00011 00001 00010 0

00011000 01000100

以大端形式表示:
0x1844

要求可读性是愚蠢的。对于这类内容,需要软件和标准(例如ASCII)才能被人类阅读。通过正确的软件和输出设备,任何内容都可以被人类阅读。


0
我之前解决了类似的问题,我会合并字符串例如(aaabb),在这个过程中它将变成(a3b1),然后我将检查所得到的压缩字符串的长度是否小于原始字符串的长度,如果是,则返回压缩字符串,否则返回原始字符串。 例如:(ab) -> (a1b1) 在这种情况下,我会返回原始字符串。 例如:(aaaaabb) -> (a5b2) 在这种情况下,我会返回压缩字符串。 以下是用于此过程的代码,时间复杂度为O(N)。
   public static String stringCompression(String str){

    StringBuilder compressed  = new StringBuilder();
    int count = 1;
    int i = 0;
    for ( i = 0; i <str.length()-1 ; i++) {
        if(str.charAt(i) == str.charAt(i+1)){
       //     System.out.println("str.charAt(i) = " + str.charAt(i));
            count++;
        }
        else {
            compressed.append(str.charAt(i)).append(count);
            count =1;
        }
    }

    if(i == str.length()-1)
        compressed.append(str.charAt(i)).append(count);

    return compressed.length() < str.length() ? new String(compressed): str;
}

你可以使用这个算法来分解数据

public static String stringDeCompression(String str){
   StringBuilder stringBuilder = new StringBuilder();
   int temp = 0;
   int k = 0;
   for (int i = 1; i <str.length() ; i+=2) {
        temp = Character.getNumericValue(str.charAt(i));
       for (int j = 0 ; j < temp ; j++) {
           stringBuilder.append(str.charAt(k));
       }
       k+=2;
    }
   return new String(stringBuilder);
}

你将如何处理输入 (a1b1)?你如何进行解压缩?只有在存在解压缩时,才不要花费时间进行数据压缩。 - greybeard
我做到了,如果你想要解压数据,你可以使用这个算法。public static String stringDeCompression(String str){ StringBuilder stringBuilder = new StringBuilder(); int temp = 0; int k = 0; for (int i = 1; i <str.length() ; i+=2) { temp = Character.getNumericValue(str.charAt(i)); for (int j = 0 ; j < temp ; j++) { stringBuilder.append(str.charAt(k)); } k+=2; } return new String(stringBuilder); } - lio
那么,哪个压缩字符串将被解压(而不是分解)成“a1b1”? - greybeard
// stringCompression("a1b1") ==> (a1b1) // stringDeCompression("a1b1") ==> (ab) 有一些错误,它应该返回相同的字符串压缩,我们该如何解决呢? - lio
无损数据压缩中通常需要权衡的是,增加所有可能字符串的平均长度,并希望减少实际出现的平均字符串长度:您必须成功地对要压缩的数据进行建模。 - greybeard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接