给出一个数字,检查数字是否形成一个带加法的方程?

时间:2014-03-17 19:38:26

标签: java c++ algorithm math

给定字符串 S ,我想知道是否存在非重叠的子串 A B C < / em>在 S 中,因此当子串被解释为十进制数时,等式 A + B = C 成立。

示例:对于S = 17512,答案是肯定的,因为12 + 5 = 17持有。

这不是一个功课问题,我试图解决这个问题,建立一个后缀数组

17512

7512

512

12

2

然后我意识到给定132,1 + 2 = 3 在选择中需要其他形式的排列吗?

你如何以有效的方式解决这个问题?

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指出):

  • 创建输入字符串的后缀树。每个节点代表一个子字符串。在每个节点中存储字符串中出现子字符串的位置的平衡二叉搜索树。您可能需要持久树来节省时间和空间。
  • 枚举A和C,但这次从最低有效数字(最右边的一端)开始。
  • 从右到左生长A和C时,跟踪B = C - A的结果。它也会从最不重要的数字增长到最重要的数字。在后缀树中搜索B。您可以一次执行此操作,因此您可以将A和C增长1位数,更新B并在O(1)的后缀树中找到它。
  • 如果B为正,则在BBST位置进行三个范围查询,以检查B是否出现在字符串中且不与A或C重叠

运行时: 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个子串是连续的,非重叠的,非负的,并且它们之间覆盖整个输入,那么就有一个二次时间解决方案。

  • 首先(暂时)假设订单是aaabbbcc,其中aaa + bbb = ccc,aaa&gt; bbb。
  • ccc的长度必须与aaa相同或最多为一个。
  • 所以aaa(len_a)的长度必须介于n / 3和n / 2之间。
  • 鉴于len_a,len_c有两种选择--- len_a或len_a + 1.
  • 鉴于这些,bbb只有一个可能的长度。 len_b = n-len_a = len_c
  • 测试这2个(n / 2 - n / 3)= n / 3个案例。
  • 由于字符串到int的转换,每个测试都是O(n)成本。

对两个排列重复上述分析(aaa> bbb v bbb> = aaa),乘以三个排列(aaa + bbb = ccc v aaa + ccc = bbb v bbb + ccc = aaa)

您可以改进测试以仅检查三个数字中最重要(或最不重要)的i数字,如果总和不可能则提前返回。假设随机分布的数字,您可能会显示此类测试的预期运行时间是不变的。 这会将整个算法转换为O(n)运行时。