如何通过迭代地从字符串中删除所有出现的某些指定单词来最小化字符串的长度

时间:2014-03-30 06:35:28

标签: string algorithm language-agnostic substring

这个问题出现在编程竞赛中,我们仍然不知道如何解决它。

问题: 给定一个字符串S和一个字符串L列表,我们希望继续删除所有可能在L中的子串的出现。我们必须最小化形成的最终字符串的长度。另请注意,删除字符串可能会启动更多删除操作。

例如,

  1. S = ccdedefcde,L = {cde} 然后回答= 1.因为我们可以通过ccdedefcde减少S - > cdefcde - > fcde - > F。
  2. S = aabaab,L = {aa,bb}然后回答= 0,因为还原可以通过aabaab进行 - > aabb - > aa - > '空字符串'
  3. S = acmmcacamapapc,L = {mca,pa}然后回答= 6,因为还原可以通过acmmcacamapapc->进行。 acmcamapapc - > acmapapc - > acmapc。
  4. S的最大长度可以是50,列表L的最大长度可以是50.

    我的方法是一个基本的递归遍历,其中我通过删除不同的子字符串返回我可以获得的最小长度。不幸的是,这种递归方法会在最坏的情况下输入,因为我们在每一步都有50个选项,递归深度为50。

    请建议一个可以解决此问题的有效算法。

3 个答案:

答案 0 :(得分:2)

这是一个产生最佳结果的多项式时间算法。由于它对我来说很方便,我将使用多项式时间CYK algorithm作为子例程,特别是根据无上下文计算字符串的最小权重解析的扩展加权制作的语法。

现在我们只需要用无上下文语法来形容这个问题。起始符号为A(通常为S,但已经拍摄),以及以下作品。

A -> N      (weight 0)
A -> A C N  (weight 0)

我很快会解释N。如果NC是终端,则A会接受常规语言N (C N)*。非终结C匹配单个终端(字符)。

C -> a  (weight 1)
C -> b  (weight 1)
C -> c  (weight 1)
...

非终结N匹配 nullable 的字符串,即可以通过删除L中的字符串将字符串缩减为空字符串的字符串。基本情况很明显。

N ->                (weight 0)

我们还为L的每个元素制作了一个作品。例如,当L = {mca, pa}时,我们有以下作品。

N -> N m N c N a N  (weight 0)
N -> N p N a N      (weight 0)

我希望它清楚如何构建迭代删除和解析之间的一对一对应关系,其中解析权重等于剩余字符串的长度。

答案 1 :(得分:0)

注意:这不是最佳解决方案,因为它不适用于示例 S=ABAABABAA, L={ABA}

<强>算法

RECURSIVE_FUNCTION ( STRING STR, STRING PATTERN) :

1. STRING LEFT = STR.SUBSTR (0, STR.FIND(PATTERN))

2. STRING RIGHT = STR.SUBSTR(STR.FIND(PATTERN), STR.LENGTH)

3. IF (RIGHT is empty) THEN RETURN LEFT

4. STRING FIN = RECUR(LEFT) + RECUR(RIGHT)

5. RETURN RECUR(FIN)

函数 SUBSTR(A,B)将返回字符串的子字符串,从索引A包含到索引B exclusive

操作 A + B是字符串A和B

的串联

功能 RECUR(A)调用相同的功能,即重复发生


示例:ccdedefcde

首先它会以RECUR(LEFT) + RECUR(RIGHT)分支:

c[cde]defcde
  /    \
 c     def[cde]
       /
      def

然后合并时RECUR(FIN)

  cdef*
  /  \
 c   def
     /
    def
在MERGE完成之前,

*将RECUR执行以下操作:

  [cde]f
       \
        f

最后ROOT调用返回f

答案 2 :(得分:0)

此代码将提供最佳解决方案 有3种情况:-
案例1 不会删除任何一个字符。
情况2 ,它已作为连续子字符串的一部分删除。
情况3 ,它被删除为与该模式集中给出的任何单词匹配的子序列的一部分,并且不属于该子序列的所有内容都首先被删除为子字符串(该字符串又属于该单词集合) )。
第三部分最棘手,需要足够的思考,而且实施起来也更加困难。
因此,对于每个子字符串,我们都需要检查该子字符串是否可以完全销毁。 函数 compute_full_recur()是确保在案例2 案例3 中可以删除子字符串的函数。
函数compute_full会处理案例1
最后,由于所有功能都是通过备忘录进行递归,因此该代码将给出超时,但是为了验证代码是否正常,我通过下载测试用例来运行它然后在我的PC上运行单个测试用例进行验证,并且它适用于所有:)。要使此代码被接受,compute_full(),compute_full_recur()和compute_ans()必须以迭代方式编写(自下而上的DP)。

BBB
AAA