假设我们有两个字符串,我们称之为s1
和s2
。现在,我们要从s2
中删除这样的子字符串,s2
将是s1
后面的子序列,并且删除的字符串的长度最小。
例如,对于s1 = "abbcabaa"
和s2 = "accbccbaa"
,此类字符串为cbcc
- 从s2
删除后,我们会留下acbaa
,这是一个s1
的后续序列。它的长度4
是最小的。
另一个例子 - s1 = "abcaacb"
,s2 = "adacaa"
。这样的字符串是"da"
- 我们在删除后留下acaa
,这是abcaacb
的子序列。它的长度2
很小。
任何解决问题的想法
答案 0 :(得分:1)
这可以在O(n + m)中求解,其中n是一个字符串的长度,m是另一个字符串的长度。
你可以通过在s1的第一个字符和s2的第一个字符上指定一个指针来实现。现在如果字符是相同的,则将两个指针向前移动,否则仅指向s1的指针。这将生成最终删除最短子串的最佳结果。现在反过来重复相同的过程。
s1: abbcabaa
match s2 from beginning: a c cbccaa
match s2 from the end: accbc c baa
每次角色匹配时,您都会保存索引。在这里,我们将有以下两个列表:
from beginning (a): [[0, 0], [1, 3]]
from the end (b): [[8, 7], [7, 6], [6, 5], [5, 3]]
现在,您可以再次使用两个指针计算删除字符串中间子字符串的最佳结果。从a中的第一个元素和b中的最后一个元素开始,在a中逐步向前移动,然后在b中向后移动,直到b中s1的索引大于a中的s1。在每个步骤计算必须删除的子串的长度。并跟踪最低限度。
第1步:pa = [0,0],pb = [5,3],因此必须删除索引1到4(包括)的子串(ccbc)
第二步:pa = [1,3],pb = [6,5],必须删除索引2到5的子串(cbcc)
最后我们可以看到有两个长度为4的最佳解决方案:ccbc和cbcc。
在这里,同样的事情转化为代码:
// returns [startIndex (inclusive), endIndex (exclusive)]
function minSubstr(s1, s2) {
let p2 = 0, a = [], b = []
for (let p1 = 0; p1 < s1.length; p1++)
if (s1[p1] == s2[p2]) {
if (p2 + 1 == s2.length)
return [0, 0] // no removal needed, s2 is subsequence of s1
a.push([p1, p2++])
}
let best = [p2, s2.length]
p2 = s2.length - 1
for (let p1 = s1.length - 1; p1 >= 0; p1--)
if (s1[p1] == s2[p2])
b.push([p1, p2--])
if (best[1] - best[0] > p2 + 1)
best = [0, p2 + 1]
let pb = b.length - 1
for (let pa = 0; pa < a.length; pa++) {
while (pb >= 0 && b[pb][0] <= a[pa][0])
pb--
if (pb < 0)
break
if (b[pb][1] - a[pa][1] - 1 < best[1] - best[0])
best = [a[pa][1] + 1, b[pb][1]]
}
return best
}
let s1 = "abbcabaa", s2 = "accbccbaa"
console.log("s1 = " + s1); console.log("s2 = " + s2)
let best = minSubstr(s1, s2)
console.log("best = " + best + " (" + s2.substring(best[0], best[1]) + ")")
s1 = "abcaacb"; s2 = "adacaa"
console.log("s1 = " + s1); console.log("s2 = " + s2)
best = minSubstr(s1, s2)
console.log("best = " + best + " (" + s2.substring(best[0], best[1]) + ")")
&#13;