动态编程测验或比较两个文本块

时间:2013-10-30 10:22:45

标签: algorithm matrix dynamic-programming

任务定义:

我尝试编写自己的diff util。我想实现内联搜索。

意味着我有两段文字。我必须将第一段( p1 )中的字符串与第二段( p2 )中的字符串相结合,使得constranted字符串中常用字的总和最大。

还有一点很重要,你不能替换字符串:我的意思是如果你将p1 [i]定义为p2 [j],那么如果k <1,则不能将p1 [k]定义为p2 [v]。我和v&lt;学家

小例子:

输入:

你有两个段落:

"Very very very very"         "Very very very"
"bla bla bla"                 "Very very very very very"
"looks like a very dump text" "One more sentence"
"simple text"                 "looks like a peace of ..."
                              "quite simple"
                              "bla bla bla bla"

...和矩阵,其中matrix [i] [j] =字符串p1 [i]和p2 [j]

中的常用字数
3 4 0 0 0 0
0 0 0 0 0 3
0 0 0 3 0 0
0 0 0 0 1 0

输出:

你需要以下一种方式来限制它们:

----------------               "Very very very"
"Very very very very"          "Very very very very very"
"bla bla bla"                  ----------------
----------------               "One more sentence"
"looks like a very dump text"  "looks like a peace of ..."
"simple text"                  "quite simple"
----------------               "bla bla bla bla"

或者你可以形成下一个矩阵:

(具有约束的字符串的索引)

p1Indexes: [0, 2, 3] p2Indexes: [1, 3 ,4]

问题:

此任务的有效算法是什么?

[不必阅读]面临的困难:

  1. 如何将索引集合传递给下一次迭代:我的意思是你需要在每次迭代时复制所有索引
  2. 如果要使用动态编程,则不仅要存储常用的数字,还要存储每个可能的迭代的两个索引集合。
  3. 解决方案:

    public void genConditionLCS() {
        int i = -1;
        int j = -1;
        while (true) {
            int[] indexes = nextIndexes(i+1, j+1);
            i = indexes[0];
            j = indexes[1];
            if (i == -1 || j == -1) break;
            firstParagraphIndexes.add(i); 
            secondParagraphIndexes.add(j);
        }
    }
    private int[] nextIndexes(int i, int j) {
        if ((i > (lcs.length-1)) || (j > (lcs[0].length-1)))
            return new int[] {-1, -1};
        int a = maxBenefit(i + 1, j);
        int b = maxBenefit(i, j + 1);
        int c = maxBenefit(i + 1, j + 1) + lcs[i][j];
        if ((a == 0) && (b == 0) && (c == 0))
            return new int[]{-1, -1};
        else if (a >= b && a >= c)
            return nextIndexes(i+1, j);
        else if (b >= a && b >= c)
            return nextIndexes(i, j+1);
        else //if (c >= a && c >= b)
            return new int[]{i, j};
    }
    
    private int maxBenefit(int i, int j) {
        if ((i > lcs.length - 1) || (j > lcs[0].length - 1)) return 0;
        int res = maxBenefit[i][j];
        if (res == -1) {
            int a = maxBenefit(i + 1, j);
            int b = maxBenefit(i, j + 1);
            int c = maxBenefit(i + 1, j + 1) + lcs[i][j];
            res = max(a, b, c);
            maxBenefit[i][j] = res;
        }
        return res;
    }
    

1 个答案:

答案 0 :(得分:3)

给定数组a[m]b[n]并给出一个代价函数:benefit(i, j),它计算元素ij之间的常用字数,问题是什么可以表示为max_benefit(i, j),这表示ij已对齐/匹配,您需要找出剩余部分的最大利益和对齐方式,即:{{1} }

现在,当您第一次为任何索引对计算max(benefit(i + 1, j + 1) + max_benefit(i + 2, j + 2), benefit(i + 2, j + 1) + max_benefit(i + 3, j + 1), benefit(i + 3, j + 1) + max_benefit(i + 4, j + 1), ..., benefit(i + 1, j + 2) + max_benefit(i + 2, j + 3), benefit(i + 1, j + 3) + max_benefit(i + 1, j + 4), ...)时,存储结果以便您不需要重新计算它。 I. e。在计算之前检查你是否有一个存储值;如果没有,请计算并存储该值。

重新遇到困难:

  1. 您可以将数组引用作为全局/类成员使用,或者可以将数组引用作为2个额外参数传递:e。 G。 max_benefitmax_benefit(i, j, a, b)。这些阵列不会被大多数语言复制。
  2. 请参阅此答案的主要部分,您只需递归计算和存储值,这样就不会重新计算。