如果我们有长度为N的字符串A
和长度为M的字符串B
,则其中M < N,我可以快速计算我必须从字符串A
中删除的最小字母数,以便字符串B
不会作为A
中的子字符串出现吗?
如果我们有很小的字符串长度,这个问题很容易暴力:你只需要从0
迭代一个位掩码到2^N
,看看B
是否作为子串发生在这里A
的后续序列。但是,当N可以达到10,000并且M可以达到1,000时,该算法显然会迅速崩溃。有更快的方法吗?
示例:A = ababaa
B = aba
。答案= 1
。删除A中的第二个a
将导致abbaa
,其中不包含B
。
编辑:用户n.m.发布了一个很好的反例:aabcc
和abc
。我们要删除单个b
,因为删除任何a
或c
都会创建字符串abc
的另一个实例。
答案 0 :(得分:2)
通过动态编程解决它。设dp [i] [j]使A [0 ... i-1]的后缀为B [0 ... j-1]以及A [0 ... i] don'的最小运算符t包含B,dp[i][j] = Infinite
索引运算符是不可能的。然后
if(A[i-1]=B[i-1])
dp[i][j] = min(dp[i-1][j-1], dp[i-1][j])
else dp[i][j]=dp[i-1][j]`,
return min(A[N][0],A[N][1],...,A[N][M-1]);`
答案 1 :(得分:0)
您可以对字符串A
进行图表搜索。对于大N和特殊输入,这可能太慢了,但它应该比指数强力算法更好。也许是BFS。
答案 2 :(得分:0)
我不确定这个问题是否还有兴趣,但我有一个想法可能会有用。
一旦我们确定问题不是找到子字符串,就是决定哪个字母更方便从字符串A中删除,我的解决方案看起来很简单:如果你发现B字符串出现在A中,你能做的最好的事情就是删除一个字符串内的字符,关闭到右边的键盘...让我们说一个最后一个。这就是为什么如果你有一个实际结束它开始的子字符串的原因,如果你在开头删除一个字符,你只需删除其中一个B出现,而你实际上可以一次删除两个。
伪cose中的算法:
String A, B;
int occ_posit = 0;
N = B.length();
occ_posit = A.getOccurrencePosition(B); // pseudo function that get the first occurence of B into A and returns the offset (1° byte = 1), or 0 if no occurence present.
while (occ_posit > 0) // while there are B into A
{
if (B.firstchar == B.lastchar) // if B starts as it ends
{
if (A.charat[occ_posit] == A.charat[occ_posit+1])
A.remove[occ_posit - 1]; // no reason to remove A[occ_posit] here
else
A.remove[occ_posit]; // here we remove the last char, so we could remove 2 occurencies at the same time
}
else
{
int x = occ_posit + N - 1;
while (A.charat[x + 1] == A.charat[x])
x--; // find the first char different from the last one
A.remove[x]; // B does not ends as it starts, so if there are overlapping instances they overlap by more than one char. Removing the first that is not equal to the char following B instance, we kill both occurrencies at once.
}
}
让我们用一个例子来解释:
A =“123456789000987654321” B =“890”
以表格形式阅读:
occ_posit: 123456789012345678901
A = "123456789000987654321"
B = "890"
第一次出现在occ_posit = 8.B在它开始时没有结束,所以它进入第二个循环:
int x = 8 + 3 - 1 = 10;
while (A.charat[x + 1] == A.charat[x])
x--; // find the first char different from the last one
A.remove[x];
同时发现A.charat11匹配A.charat [10](=“0”),因此x变为9然后在退出时为A.charat [10]与A.charat9不匹配。然后成为:
A =“12345678000987654321”
没有更多的出现。
让我们尝试另一个: A =“abccccccccc” B =“abc”
第一次出现在occ_posit = 1.B在它开始时没有结束,所以它进入第二个循环:
int x = 1 + 3 - 1 = 3;
while (A.charat[x + 1] == A.charat[x])
x--; // find the first char different from the last one
A.remove[x];
同时发现A.charat4匹配A.charat [3](=“c”),因此x变为2然后在退出时为A.charat [3]与A.charat2不匹配。然后成为:
A =“accccccccc”
让我们尝试重叠:
A =“abcdabcdabff” B =“abcdab”
算法导致:A =“abcdacdabff”没有更多的出现。
最后,一个字母重叠:
A =“abbabbabbabba” B =“abba”
B在开始时结束,因此它进入第一个if:
if (A.charat[occ_posit] == A.charat[occ_posit+1])
A.remove[occ_posit - 1]; // no reason to remove A[occ_posit] here
else
A.remove[occ_posit]; // here we remove the last char, so we could remove 2 occurencies at the same time
允许删除B实例的最后一个“a”。所以:
步骤1步:A =“abbbbabbabba” 2°步骤:A =“abbbbabbbba”,我们完成了。希望这有帮助
编辑:请注意,当您在搜索时接近A端时,必须稍微纠正algotirhm以防止出错,但这只是一个简单的编程问题。
答案 3 :(得分:0)
这是我想出的草图。
首先,如果A包含在B中找不到的任何符号,则将A拆分为一堆较小的字符串,其中只包含B中找到的那些字符。将算法应用于每个较小的字符串,然后将它们粘合在一起得到总结果。这确实可以作为优化。
接下来,检查A是否包含B中的任何一个。如果没有,则表示您已完成。如果A = B,则删除所有这些。
我认为相对贪婪的算法可能有用。
首先,在A中标记属于至少一次出现的B的所有符号。设A = aabcbccabcaa,B = abc。粗体表示这些标记的字符:
abc bcc abc aa。如果有重叠,请标记所有可能的。这个操作是天真的近似(A-B)操作,但我相信它可以在(A / B)操作中完成。
考虑删除A中的每个标记字母:a abc bcc abc aa。
检查删除标记的字母是否会减少标记字母的数量。您只需要检查可能受删除字母影响的子字符串。如果B的长度为4,则只有在检查x时才需要删除从以下位置开始的子串:
-------x------
^^^^
无论是否存在x,都会存在任何进一步的左或右。
例如:
在以下字符串中标记[a]:a [a] bc bcc abc aa。
它的删除产生abcbccabcaa,当标记时产生 abc bcc abc aa,其具有相同数量的标记字符。由于此操作仅需要相对数量,因此对于每个所选字母,可以在大约2B时间内完成。对于每个,分配两者之间的相对差异。选择一个最大的任意一个并删除它。重复直到完成。每次通过大约最多2AB次操作,最多A次通过,总时间约为2A ^ 2 B.
在上面的示例中,分配了这些值:
aabcbccabcaa
033 333
所以随意删除第一个标记的b给你:aacbccabcaa。如果你重复这个过程,你会得到:
aacbccabcaa
333
最终结果已经完成。
我相信算法是正确的最小化。我认为,只要A只需要一次删除,算法必须才是最佳的。在这种情况下,减少最可能的匹配(即:所有这些)的字母应该是最好的。不过,我无法提出这样的证据。我有兴趣找到最优的反例。
答案 4 :(得分:0)
查找主字符串中每个子字符串的indeces。
然后使用动态编程算法(所以记住中间值),从主字符串中删除属于子字符串一部分的每个字母,将1加到计数中,然后重复。
你可以找到这些字母,因为它们在每个匹配索引的缺口+ B的长度内。
A = ababaa
B = aba
count = 0
indeces = (0, 2)
A = babaa, aabaa, abbaa, abbaa, abaaa, ababa
B = aba
count = 1
(2nd abbaa is memoized)
indeces = (1), (1), (), (), (0), (0, 2)
answer = 1
您可以更进一步,并尝试记住子字符串的子字符串匹配,但这可能实际上不是性能提升。
不确定确切的界限,但不应该花费太长时间计算。
答案 5 :(得分:-1)
好的,我想我有一个简单的解决方案 我要假装A,B只是二进制数字串。
A= 011010101001001101
B= 010
在A上应用XNOR过滤器,结果为B.结果将为 C 假设B的原点位于其中心 (这意味着在A中查找B。如果找到匹配项,请将1 in C放入该位置。)
A= 011010101001001101
C= 000010101001000000
简单地说,C显示A包含B的位置 例如,您可以删除C所示位置中的所有字符,这样可以解决您的问题。但它不是最佳解决方案。
但找到最佳解决方案很容易 好的,现在问题更简单了。我可以解释一下这些算法问题:
这不是新问题,现有解决方案。应用一个这样的解决方案。
这将产生以下结果。 D 显示已删除1的位置:
C= 000010101001000000
D= 000000100001000000
计算D中的1的数量 - > 2.这意味着您可以从A中删除2个元素,因此B不是A的子字符串。