具有间隙的最长的子串

时间:2017-06-10 20:25:18

标签: algorithm substring lis

我遇到了如下指定的问题:

A 成为正整数序列 设 B A 的子字符串 让 C 成为从 A 中删除 B 创建的序列。
对于给定的 A ,找到 C 的最长(严格)子串的长度,其中 B 可以任意选择。

例如,让 A = [3 2 5 7 1 2 8 1] 。如果我们设置 B = [1 2] ,那么 C = [3 2 5 7 8 1] 并且其增长最长的子串是 [2 5 7 8] ,长度为4. 4是答案,因为没有其他 B 会导致更好的解决方案。

我无法找到解决问题的算法(当然是多项式时间:)),但我相信它会是最长的后续子序列问题的一些变化。
请帮我找一个好的算法或给我一些提示或参考。

3 个答案:

答案 0 :(得分:1)

制作两个长度为n - noskipskip的辅助数组。

元素noskip[i]包含以i结尾的最长增长子字符串的长度,而不会删除原始字符串中的任何内容。在O(n)中算法的第一次传递中计算此数组。

元素skip[i]包含以i结尾的最长增长子字符串的长度,其中跳过中间的单个组。通过在O(n 2 )中回顾noskip的值,在算法的第二次运行中计算此数组。

skip数组的最高值是您问题的答案。

以下是两个数组如何查找输入:

data:   3 2 5 7 1 2 8 1
noskip: 1 1 2 3 1 2 3 1
skip:   1 1 2 3 1 2 4 1

当我们查看8时,我们会重复data,寻找j < idata[j] < data[i]noskip[j]+1 > skip[i]这样的元素。如果skip[i],则skip[i-1]的初始值设置为data[i] > data[i-1],否则设置为1

以下是Java中的示例实现:

int[] data = new int[] {3, 2, 5, 7, 1, 2, 8, 1};
int[] noskip = new int[data.length];
int[] skip = new int[data.length];
noskip[0] = 1;
for (int i = 1 ; i != skip.length ; i++) {
    noskip[i] = data[i] > data[i-1] ? noskip[i-1]+1 : 1;
}
skip[0] = 1;
int res = 1;
for (int i = 1 ; i != data.length ; i++) {
    skip[i] = data[i] > data[i-1] ? skip[i-1]+1 : 1;
    for (int j = i-1 ; j >= 0 ; j--) {
        if (data[j] < data[i] && noskip[j]+1 > skip[i]) {
            skip[i] = noskip[j]+1;
        }
    }
    res = Math.max(res, skip[i]);
}
System.out.println(res);

Demo.

答案 1 :(得分:1)

在输入数组中进行单次迭代时:

  • 设置数组smallest[n],其中smallest[i]表示长度为i的增长子字符串可以结束的最小元素(例如,如果smallest[3] = 5,表示长度为3的子字符串以5结尾,并且没有长度为3的子字符串以4结尾,否则smallest[3]将为4

    到目前为止,我们可以跟踪最长的子串i,如果该元素大于当前元素,则只需替换smallest[i]

    关于这个数组的重要说明:这个数组中的元素将严格按顺序增加,也就是说,如果数组中存在以元素i结尾的长度为x的子字符串,不再包含一个等于或小于x的元素的子字符串(这是因为较长的子字符串将包含一个长度为i的子字符串,该子字符串以小于x的元素结尾,因此{ {1}}将是该元素而不是smallest[i])。

  • 除了这个数组,还要保留一个二进制搜索树(BST),它将元素映射到子串长度(基本上与数组相反)。

    更新x时,还要从BST中删除旧元素并插入新元素。

    (到目前为止所有这些都是关于原始数组A中的子串,而不是删除后的数组C)

  • 使用这个,我们可以通过查找小于BST中该元素的最大元素并在其中添加1来找到C中任意元素(直接在某个B之后)的C中最长的子串smallest长度。

  • C中任何给定元素结尾的最长子字符串将只是前一个元素中结尾的最长子字符串1 +(如果它更小,否则为0)和longestSSAfterB

    C中最长的子串只是我们在上面找到的最长的子串。

所有这些都需要longestSSAfterB

示例:

O(n log n)

答案 2 :(得分:0)

我对此问题的解释不多,但我认为这个O(nlogn)解决方案可行。

对于A,维护数组说prefsuff

pref[i]包含您可以从i开始创建的增长最长的子阵列(LIS)。同样地,suff[i]包含您可以在i结束时创建的LIS。

可以在O(n)

中创建它们

然后找到(i,j)的最佳组合,suff[i] + pref[j]最大,i<j and arr[i]<arr[j]。这可以通过迭代每个i找到,并通过将j数组存储为bst来查找每个pref

对于您的示例,A = [3 2 5 7 1 2 8 1]

然后,

3 2 5 7 1 2 8 1 (arr)
1 1 2 3 1 2 3 1 (suff)
1 3 2 1 3 2 1 1 (pref)

如你所说的那样删除1,2给出了suff [3] + pref [6] = 3 + 1 = 4。