给定字符串 S ,我想知道是否存在非重叠的子串 A , B 和 C < / em>在 S 中,因此当子串被解释为十进制数时,等式 A + B = C 成立。
示例:对于S = 17512,答案是肯定的,因为12 + 5 = 17持有。
这不是一个功课问题,我试图解决这个问题,建立一个后缀数组
17512
7512
512
12
2
然后我意识到给定132,1 + 2 = 3 在选择中需要其他形式的排列吗?
你如何以有效的方式解决这个问题?
答案 0 :(得分:2)
让 S 为数字的十进制表示。如果 n = | S | 足够小(<500左右),则可以使用以下算法:
让我们从等式A + B = C(其中我们假设w.l.o.g.A> B)中枚举A和C.我们知道它们需要大小相同(加/减一位),因此枚举可能性是一个三次运算(有 O(n 3 )候选)。对于每个候选对(A,C),我们需要检查B = C - A
是否在字符串中并且不与任何 A 重叠或 C 子串。我们可以使用基数10中的算术计算线性时间的差异。
棘手的部分是检查 B 是否是不重叠 A 或 C 的子字符串。 A 和 C 将字符串拆分为3个部分:
S = xAyCz
如果我们巧妙地枚举它们,固定的起始位置和减小的大小,我们可以保持部分x的suffix automata和部分y和z的反转。
现在我们可以检查线性时间是否 B = C - A (或其反向)存在于三个部分之一中。
此方法的时间复杂度:Θ(n 4 )。
这有一个变化,稍微复杂一点,但更快(感谢Evgeny指出):
运行时: O(n 3 log n)。
更新关于需要使用所有字符的简化版本:
我们首先意识到,如果我们在基数10工作,我们可以在线性时间内对字符串的子串进行算术。
现在我们想要找到分裂点 a&lt; b ,这样你的三个子串就是 A = s 1 ... s a , B = s < sub> a + 1 ... s b 和 C = s b + 1 ... s n 子>
我们可以证明 a 和 b 只有一定数量的候选者,因为所有三个部分的大小必须大致相同才能保持。
使用任意精度算术,我们可以轻松地尝试所有候选对(a,b),并且对于每个候选对,找到 M = max(A,B,C)。然后检查 M 是否是其他两个数字的总和。
总时间复杂度:Θ(n)。
答案 1 :(得分:1)
如果你被允许以原始给定顺序从数字的数字子集形成子串,只要你的数字在2个加数和总和中没有重叠,那么我相信你的问题是NP完全的。我认为如果给出目标总和,并且你所要做的就是找到两个非重叠的数字子串,这些数字加起来就是目标总和。但是我还没有NP完整性的证据。
如果您的数字子串必须是连续的,那么情况要好得多。您可以在O(n ^ 6)时间内搜索2个加数和1个和的所有组合作为数字的起点和终点,当然可以进行改进,例如,对于给定的目标总和,您只需要搜索一对子串,这些子串的最大长度加上目标总和的长度正好或减去1.
更新:如果你需要找到3个非重叠的连续子串,它们给你求和公式,那么你可以散列所有O(n ^ 2)子串值,然后散列所有求和对的总和,看看是否目标总和在您的哈希表中。如果是这样,那么您只需要检查加数开始和结束索引是否与summand索引重叠。最坏情况时间为O(n ^ 6),随机输入的预期运行时间为O(n ^ 5)。
答案 2 :(得分:0)
假设(在你的两个例子中)你的3个子串是连续的,非重叠的,非负的,并且它们之间覆盖整个输入,那么就有一个二次时间解决方案。
对两个排列重复上述分析(aaa> bbb v bbb> = aaa),乘以三个排列(aaa + bbb = ccc v aaa + ccc = bbb v bbb + ccc = aaa)
您可以改进测试以仅检查三个数字中最重要(或最不重要)的i数字,如果总和不可能则提前返回。假设随机分布的数字,您可能会显示此类测试的预期运行时间是不变的。 这会将整个算法转换为O(n)运行时。