Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 求最小长度RLE_Algorithm_Dynamic Programming_Run Length Encoding - Fatal编程技术网

Algorithm 求最小长度RLE

Algorithm 求最小长度RLE,algorithm,dynamic-programming,run-length-encoding,Algorithm,Dynamic Programming,Run Length Encoding,经典的RLE算法通过使用数字来表示数字后面的字符在文本中该位置出现的次数来压缩数据。例如: aaabbaabbecee=>3a2b3a2b1c1c1e 但是,在上面的示例中,该方法会导致压缩文本使用更多的空间。更好的方法是使用数字来表示数字后面的子字符串在给定文本中出现的次数。例如: aaabbaabbecee=>2aabb2ce(“AAABB”两次,然后“CE”两次) 现在,我的问题是:我如何实现一个高效的算法,用这个方法找出最优RLE中的最小字符数?蛮力方法存在,但我需要更快的方法(最多O(

经典的RLE算法通过使用数字来表示数字后面的字符在文本中该位置出现的次数来压缩数据。例如:

aaabbaabbecee=>3a2b3a2b1c1c1e

但是,在上面的示例中,该方法会导致压缩文本使用更多的空间。更好的方法是使用数字来表示数字后面的子字符串在给定文本中出现的次数。例如:

aaabbaabbecee=>2aabb2ce(“AAABB”两次,然后“CE”两次)


现在,我的问题是:我如何实现一个高效的算法,用这个方法找出最优RLE中的最小字符数?蛮力方法存在,但我需要更快的方法(最多O(length2))。也许我们可以使用动态编程?

我认为动态编程在这里不起作用,因为在解决方案中,子字符串的长度可能是整个字符串长度的一半。看起来你需要使用蛮力。
有关相关问题,请查看。利用子串寻找最小编码是一种有效的算法

找到匹配子字符串的非常聪明的方法可能会导致考虑后缀树和后缀数组。考虑后缀数组和压缩可能会导致出现错误。这可能是提高运行长度编码的最优雅的方法。

对RLE压缩数据进行编码的一种非常常见的方法是将一个特殊字节指定为“DLE”(对不起,我不记得该术语代表什么),这意味着“下一个是一个字节后的计数”

这样,只需要对重复序列进行编码。通常,选择DLE符号是为了将其在未压缩数据中自然出现的可能性降至最低

对于您最初的示例,让我们将句号(或点)设置为DLE,这将对您的示例进行如下编码:

AAABBAAABBCECE => 3A2B3A2B1C1E1C1E <-- your encoding
AAABBAAABBCECE => .3ABB.3ABBCECE   <-- my encoding
aaabbaabbecee=>3a2b3a2b1c1c1c1e.3ABB.3abbcee可以通过动态规划在二次时间内完成

下面是一些Python代码:

import sys
import numpy as np

bignum = 10000

S = sys.argv[1] #'AAABBAAABBCECE'                                                                                                                              
N = len(S)

# length of longest substring match bet s[i:] and s[j:]                                                                                                        
maxmatch = np.zeros( (N+1,N+1), dtype=int)

for i in xrange(N-1,-1,-1):
  for j in xrange(i+1,N):
    if S[i] == S[j]:
      maxmatch[i,j] = maxmatch[i+1,j+1]+1

# P[n,k] = cost of encoding first n characters given that last k are a block                                                                                   
P = np.zeros( (N+1,N+1),dtype=int ) + bignum
# Q[n] = cost of encoding first n characters                                                                                                                   
Q = np.zeros(N+1, dtype=int) + bignum

# base case: no cost for empty string                                                                                                                          
P[0,0]=0
Q[0]=0

for n in xrange(1,N+1):
  for k in xrange(1,n+1):
    if n-2*k >= 0:
#     s1, s2 = S[n-k:n], S[n-2*k:n-k]                                                                                                                          
#     if s1 == s2:                                                                                                                                             
      if maxmatch[n-2*k,n-k] >=k:
        # Here we are incrementing the count: C x_1...x_k -> C+1 x_1...x_k                                                                                     
        P[n,k] = min(P[n,k], P[n-k,k])
        print 'P[%d,%d] = %d' % (n,k,P[n,k])
    # Here we are starting a new block: 1 x_1...x_k                                                                                                            
    P[n,k] = min(P[n,k], Q[n-k] + 1 + k)
    print 'P[%d,%d] = %d' % (n,k,P[n,k])
  for k in xrange(1,n+1):
    Q[n] = min(Q[n], P[n,k])

  print

print Q[N]
您可以通过记住沿途的选择来重建实际编码

我遗漏了一个小问题,即如果C很大,我们可能需要使用额外的字节来保存C+1。如果您使用的是32位整数,那么在该算法运行时可行的任何上下文中都不会出现这种情况。如果您有时使用较短的整数来节省空间,那么您将不得不考虑它,并可能根据最新C的大小向表中添加另一个维度。理论上,这可能会添加一个对数(N)因子,但我认为这在实践中并不明显

编辑:为了@Moron的好处,这里有相同的代码和更多的打印语句,这样你可以更容易地看到算法在想什么:

import sys
import numpy as np

bignum = 10000

S = sys.argv[1] #'AAABBAAABBCECE'                                                                                                                              
N = len(S)

# length of longest substring match bet s[i:] and s[j:]                                                                                                        
maxmatch = np.zeros( (N+1,N+1), dtype=int)

for i in xrange(N-1,-1,-1):
  for j in xrange(i+1,N):
    if S[i] == S[j]:
      maxmatch[i,j] = maxmatch[i+1,j+1]+1

# P[n,k] = cost of encoding first n characters given that last k are a block                                                                                   
P = np.zeros( (N+1,N+1),dtype=int ) + bignum
# Q[n] = cost of encoding first n characters                                                                                                                   
Q = np.zeros(N+1, dtype=int) + bignum

# base case: no cost for empty string                                                                                                                          
P[0,0]=0
Q[0]=0

for n in xrange(1,N+1):
  for k in xrange(1,n+1):
    if n-2*k >= 0:
#     s1, s2 = S[n-k:n], S[n-2*k:n-k]                                                                                                                          
#     if s1 == s2:                                                                                                                                             
      if maxmatch[n-2*k,n-k] >=k:
        # Here we are incrementing the count: C x_1...x_k -> C+1 x_1...x_k                                                                                     
        P[n,k] = min(P[n,k], P[n-k,k])
        print "P[%d,%d] = %d\t I can encode first %d characters of S in only %d characters if I use my solution for P[%d,%d] with %s's count incremented" % (n\
,k,P[n,k],n,P[n-k,k],n-k,k,S[n-k:n])
    # Here we are starting a new block: 1 x_1...x_k                                                                                                            
    P[n,k] = min(P[n,k], Q[n-k] + 1 + k)
    print 'P[%d,%d] = %d\t I can encode first %d characters of S in only %d characters if I use my solution for Q[%d] with a new block 1%s' % (n,k,P[n,k],n,Q[\
n-k]+1+k,n-k,S[n-k:n])
  for k in xrange(1,n+1):
    Q[n] = min(Q[n], P[n,k])

  print
  print 'Q[%d] = %d\t I can encode first %d characters of S in only %d characters!' % (n,Q[n],n,Q[n])
  print


print Q[N]
ABCDBCD上的最后几行输出如下:

Q[13] = 7        I can encode first 13 characters of S in only 7 characters!

P[14,1] = 9      I can encode first 14 characters of S in only 9 characters if I use my solution for Q[13] with a new block 1C
P[14,2] = 8      I can encode first 14 characters of S in only 8 characters if I use my solution for Q[12] with a new block 1BC
P[14,3] = 13     I can encode first 14 characters of S in only 13 characters if I use my solution for Q[11] with a new block 1DBC
P[14,4] = 13     I can encode first 14 characters of S in only 13 characters if I use my solution for Q[10] with a new block 1CDBC
P[14,5] = 13     I can encode first 14 characters of S in only 13 characters if I use my solution for Q[9] with a new block 1BCDBC
P[14,6] = 12     I can encode first 14 characters of S in only 12 characters if I use my solution for Q[8] with a new block 1ABCDBC
P[14,7] = 16     I can encode first 14 characters of S in only 16 characters if I use my solution for Q[7] with a new block 1DABCDBC
P[14,8] = 16     I can encode first 14 characters of S in only 16 characters if I use my solution for Q[6] with a new block 1CDABCDBC
P[14,9] = 16     I can encode first 14 characters of S in only 16 characters if I use my solution for Q[5] with a new block 1BCDABCDBC
P[14,10] = 16    I can encode first 14 characters of S in only 16 characters if I use my solution for Q[4] with a new block 1ABCDABCDBC
P[14,11] = 16    I can encode first 14 characters of S in only 16 characters if I use my solution for Q[3] with a new block 1DABCDABCDBC
P[14,12] = 16    I can encode first 14 characters of S in only 16 characters if I use my solution for Q[2] with a new block 1CDABCDABCDBC
P[14,13] = 16    I can encode first 14 characters of S in only 16 characters if I use my solution for Q[1] with a new block 1BCDABCDABCDBC
P[14,14] = 15    I can encode first 14 characters of S in only 15 characters if I use my solution for Q[0] with a new block 1ABCDABCDABCDBC

Q[14] = 8        I can encode first 14 characters of S in only 8 characters!

P[15,1] = 10     I can encode first 15 characters of S in only 10 characters if I use my solution for Q[14] with a new block 1D
P[15,2] = 10     I can encode first 15 characters of S in only 10 characters if I use my solution for Q[13] with a new block 1CD
P[15,3] = 11     I can encode first 15 characters of S in only 11 characters if I use my solution for P[12,3] with BCD's count incremented
P[15,3] = 9      I can encode first 15 characters of S in only 9 characters if I use my solution for Q[12] with a new block 1BCD
P[15,4] = 14     I can encode first 15 characters of S in only 14 characters if I use my solution for Q[11] with a new block 1DBCD
P[15,5] = 14     I can encode first 15 characters of S in only 14 characters if I use my solution for Q[10] with a new block 1CDBCD
P[15,6] = 14     I can encode first 15 characters of S in only 14 characters if I use my solution for Q[9] with a new block 1BCDBCD
P[15,7] = 13     I can encode first 15 characters of S in only 13 characters if I use my solution for Q[8] with a new block 1ABCDBCD
P[15,8] = 17     I can encode first 15 characters of S in only 17 characters if I use my solution for Q[7] with a new block 1DABCDBCD
P[15,9] = 17     I can encode first 15 characters of S in only 17 characters if I use my solution for Q[6] with a new block 1CDABCDBCD
P[15,10] = 17    I can encode first 15 characters of S in only 17 characters if I use my solution for Q[5] with a new block 1BCDABCDBCD
P[15,11] = 17    I can encode first 15 characters of S in only 17 characters if I use my solution for Q[4] with a new block 1ABCDABCDBCD
P[15,12] = 17    I can encode first 15 characters of S in only 17 characters if I use my solution for Q[3] with a new block 1DABCDABCDBCD
P[15,13] = 17    I can encode first 15 characters of S in only 17 characters if I use my solution for Q[2] with a new block 1CDABCDABCDBCD
P[15,14] = 17    I can encode first 15 characters of S in only 17 characters if I use my solution for Q[1] with a new block 1BCDABCDABCDBCD
P[15,15] = 16    I can encode first 15 characters of S in only 16 characters if I use my solution for Q[0] with a new block 1ABCDABCDABCDBCD

Q[15] = 9        I can encode first 15 characters of S in only 9 characters!

你确定吗?最坏情况下,长度将为原始长度+1(“1”+给定字符串)。我不明白为什么这意味着动态规划不起作用。我认为这个问题仍然表现出最优的子结构:如果我们能找到字符串的一部分的答案,我们可以在更大的部分的答案中使用它。我只是不知道怎么做。通过用长度为1的链接替换每个字符,形成一个实际上是一条直线链接的图形。现在,在每一个可能进行游程编码的点上,创建一个额外的链接,绕过游程编码扩展到的字符,其长度是编码所需的字符数。通过这个图的最短路径是最短编码-但我没有找到一种快速的方法来找到哪些子字符串可以被游程编码替换-到目前为止,其他任何人也没有。这绝对可能是有效的-我的意思是O(L^2)或O(L^2 log L)或O(L^3)下的某个东西,正如我第一次在编程竞赛中看到的,长度L约为5000,时间限制为几百毫秒。我认为使用一个图是过分的,并且最终会比蛮力解决方案更慢,蛮力解决方案为每个角色测试从该角色开始存在多少特定长度的重复子字符串(尝试所有长度),主要是因为构建图仍然需要这样做…我真的不明白BWT如何帮助我,甚至它与RLE的关系。。。匹配子字符串的聪明方法可以等待。在我发布的问题的解决方案中,我如何使用子字符串匹配?BWT是一种“部分排序”-输出将比输入有更多的字符运行,因此RLE会更好。但您仍然使用了比最佳值更多的字符。您的编码使用14个字符,而我的第二个编码使用9个字符。编码连续重复的子字符串通常是最好的方法。我对一种算法感兴趣,该算法通过执行我在作品中描述的操作,使我能够获得最少的字符数——“以下八位字节是原始数据”(下一个答案似乎使用了一位数长度),您能详细说明如何索引输入字符串S和其他变量吗?当你说“to x”时,你是也包括x还是只包括x-1?另外,这个:如果S[n-k:n]==S[n-2*k:n-k]在我看来并不正确。当n=2和k=1时,用S[0:1]测试S[1:2]。您不应该进行测试以确保没有字符重叠吗?我得到了一些错误的答案,就像你说的,比如我在我的OP中发布的字符串,我得到了长度14,这是错误的。即使我加/减1以避免比较重叠字符,我也得到了10。我稍微简化了一些事情,并用python实现了它,它在aaabbaabcee上得到了正确的答案。在Python中,S[a:b]表示字符a到b-1。xrange(a,b)从a到b-1的计数类似。这就是我最初对S[n-k:n]表示法的意图,但我同意,如何解释伪代码中的歧义从来都不是很清楚。@食指:您是否选择了可以作为重复块写入的最大前缀?怎么