3

任务定义:

我尝试编写自己的差异工具。我想实现内联搜索。

意味着我有两段文字。我必须将第一段(p1)中的字符串限制为第二段(p2)中的字符串,以使受限制字符串中的常用单词总和最大。

还有一点很重要,你不能替换字符串:我的意思是如果你将 p1[i] 限制为 p2[j],那么你不能将 p1[k] 限制为 p2[v] 如果 k < i 和 v < j.

小例子:

输入:

你有两个段落:

"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. 如果你想使用动态规划,你不仅需要存储一个常见的 wors 编号,还需要为每个可能的迭代存储两个索引集合。

解决方案:

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;
}
4

1 回答 1

3

给定数组a[m]andb[n]给定一个成本函数:benefit(i, j)它计算元素i和之间的常用词的数量j,您的问题可以表述为max_benefit(i, j)这意味着ij是对齐/匹配的,您需要找出剩余部分的最大收益和对齐方式,这是: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), ...)

现在,当您第一次计算max_benefit任何一对索引时,存储结果以便您不需要重新计算它。IE。在计算之前检查您是否有存储值;如果不是,则计算它并存储该值。

再面临困难:

  1. 您可以将数组引用用作全局/类成员,或者您可以将数组引用作为 2 个额外参数传递:例如max_benefit(i, j, a, b)benefit(i, j, a, b). 大多数语言都不会复制数组。
  2. 看到这个答案的主要部分,你只是递归地计算和存储值,这样你就不会重新计算。
于 2013-10-30T10:40:29.163 回答