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

ash*_*k v 6 c++ java algorithm math

如果给定字符串小号,我想找出是否有非重叠子,Ç小号,使得方程A + B = C时的子串被解释为十进制数成立.

示例:对于S = 17512,答案是肯定的,因为12 + 5 = 17成立.

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

17512

7512

512

12

2

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

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

Nik*_* B. 2

S为该数字的十进制表示形式。如果n = |S| 足够小(<500左右),可以使用以下算法:

\n\n

让我们从方程 A + B = C 中枚举 A 和 C(其中我们假设 wlog A > B)。我们知道它们的大小需要大致相同(加/减一位数),因此枚举可能性是三次运算(有O(n 3 )个候选者)。

\n\n

对于每个候选对(A, C),我们需要检查 是否B = C - A在字符串中并且不与任何AC子串重叠。我们可以使用以 10 为基数的算术来计算线性时间的差异。

\n\n

棘手的部分是检查B是否是不与AC重叠的子字符串。AC将字符串分成 3 部分:

\n\n
S = xAyCz\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我们以一种巧妙的方式枚举它们,具有固定的起始位置和递减的大小,我们可以维护部分 x 的后缀自动机以及部分 y 和 z 的反转。

\n\n

现在我们可以在线性时间内检查B = C - A(或其相反)是否存在于三个部分之一中。

\n\n

这种方法的时间复杂度:\xce\x98(n 4 )

\n\n

有一个变体,稍微复杂一些,但速度更快(感谢 Evgeny 指出):

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

运行时间:O(n 3 log n)

\n\n

更新:关于需要使用所有字符的简化版本:

\n\n

我们首先意识到,如果我们以 10 为基数,我们可以在线性时间内对字符串的子字符串进行算术运算。

\n\n

现在我们想要找到分裂点a < b,这样你的三个子字符串是A = s 1 ...s aB = s a+1 ...s bC = s b+1 ...s名词

\n\n

我们可以证明ab的候选数只有恒定数量,因为所有三个部分必须具有大致相同的大小才能使方程成立。

\n\n

使用任意精度算术,我们可以轻松尝试所有候选对 (a,b),并针对每个候选对找到M = max(A,B,C)。然后只需检查M是否是其他两个数字的和。

\n\n

总时间复杂度:\xce\x98(n)

\n