给定一个数字,检查数字是不是形成一个加法方程?
Posted
技术标签:
【中文标题】给定一个数字,检查数字是不是形成一个加法方程?【英文标题】:Given a number check if digits form an equation with addition?给定一个数字,检查数字是否形成一个加法方程? 【发布时间】:2014-03-17 19:38:26 【问题描述】:给定一个字符串S,我想知道是否有不重叠的子字符串A、B和C 在 S 中,因此当子字符串被解释为十进制数时,等式 A + B = C 成立。
示例:对于 S = 17512,答案是肯定的,因为 12 + 5 = 17 成立。
这不是一个家庭作业问题,我已经尝试过构建一个后缀数组来解决这个问题
17512
7512
512
12
2
但后来我意识到给定 132, 1 + 2 = 3 在选择中是否需要其他形式的排列?
你如何有效地解决这个问题?
【问题讨论】:
你也能有 1 + 7 = 5 + 1 + 2 吗? 所有数字都必须在等式中吗?此外,12
不是数字。你能以任意顺序组成任意数字的数字吗?
是的 12 不是数字,可以取多个数字,只要一个子字符串与另一个子字符串相加到结果中的子字符串即可。我将编辑问题
看起来你需要的更像是AST,而不是减少到'digits' ...
重叠子串怎么样? 1+1=2 是“12”的有效方程式吗? 23+34=57 是“23457”的有效方程式吗?必须使用所有字符吗? 1+2=3 是“1234”的有效方程吗?
【参考方案1】:
令 S 为数字的十进制表示。如果 n = |S| 足够小(
让我们从等式 A + B = C 中枚举 A 和 C(我们假设 w.l.o.g. A > B)。我们知道它们的大小需要大致相同(加/减一位数),因此枚举可能性是三次运算(有 O(n3)候选人)。
对于每个候选对 (A, C),我们需要检查 B = C - A
是否在字符串中并且不与任何 A 或 重叠>C 个子字符串。我们可以使用以 10 为底的算术来计算线性时间的差异。
棘手的部分是检查 B 是否是不重叠 A 或 C 的子字符串。 A 和 C 将字符串分成 3 部分:
S = xAyCz
如果我们以巧妙的方式枚举它们,固定起始位置并减小大小,我们可以保持 x 部分的 suffix automata 以及 y 和 z 部分的倒数。
现在我们可以在线性时间中检查 B = C - A(或其相反)是否存在于三个部分之一中。
这种方法的时间复杂度:Θ(n4).
这里有一个变体,稍微复杂一些,但速度更快(感谢 Evgeny 指出):
创建输入字符串的后缀树。每个节点代表一个子串。在每个节点中存储子字符串在字符串中出现的位置的平衡二叉搜索树。您可能需要在此处使用持久树以节省时间和空间。 枚举 A 和 C,但这次从最低有效数字(最右端)开始。 在从右到左增长 A 和 C 的同时,跟踪 B = C - A 的结果。它也会从最低有效位增长到最高有效位。在后缀树中搜索 B。您可以一次执行一位,因此您可以使 A 和 C 增长 1 位,更新 B 并将其定位在 O(1) 中的后缀树中。 如果B是正数,在位置的BBST中做三个范围查询,检查B是否出现在字符串中,并且不与A或C重叠运行时间:O(n3 log n).
更新:关于需要使用所有字符的简化版本:
我们首先意识到,如果我们以 10 为底,我们可以在线性时间内对字符串的子字符串进行算术运算。
现在我们要找到分裂点a,这样你的三个子串就是A = s1...sa 、B = sa+1...sb 和 C = sb+1...sn.
我们可以证明 a 和 b 只有恒定数量的候选对象,因为这三个部分的大小必须大致相同才能使等式成立。
使用任意精度算术,我们可以轻松地尝试所有候选对 (a,b),并为每个候选对找到 M = max(A,B,C)。然后只需检查 M 是否是其他两个数字的总和。
总时间复杂度:Θ(n).
【讨论】:
这假设使用了所有数字,我认为这不是问题假设的一部分。它还假设数字用于连续子集中,这可能是问题假设的一部分,也可能不是。 @user2566092:子字符串对我来说意味着“连续”。 您仍然假设使用了所有数字,这可能不是 OP 的意图。 @user2566092 引用评论:“不需要使用所有字符” 好的,所以我们同意,OP 不需要使用所有字符,但您的解决方案假定使用所有字符。【参考方案2】:如果允许您按照原始给定顺序从任意数字子集形成子字符串,只要您的数字在 2 个加法和总和中不重叠,那么我相信您的问题是 NP 完全的。我认为即使给出了目标总和也是如此,并且您所要做的就是找到两个不重叠的数字子串,它们加起来就是目标总和。但是我还没有证明 NP 完全性。
如果您的数字子串必须是连续的,那么情况会好得多。您可以在 O(n^6) 时间内搜索 2 个 summands 和 1 summands 的所有组合以查找数字的起点和终点,当然可以进行改进,因为例如对于给定的目标总和,您只需要搜索最大长度与目标总和的长度之和正好等于或负 1 的子字符串对。
更新:如果您需要找到 3 个不重叠的连续子字符串来提供求和公式,那么您可以散列所有 O(n^2) 子字符串值,然后散列所有对和数的总和,看看是否目标总和在您的哈希表中。如果是这样,那么您只需要检查加法开始和结束索引是否与加法索引重叠。最坏情况的时间是 O(n^6),随机输入的预期运行时间是 O(n^5)。
【讨论】:
@NiklasB。我假设恒定时间算术和散列,这可能不是一个有效的假设。相应更新。【参考方案3】:假设(在您的两个示例中)您的 3 个子字符串是连续的、不重叠的、非负的,并且它们之间覆盖了整个输入,那么就有一个二次时间解。
首先(暂时)假设顺序是 aaabbbccc,其中 aaa+bbb=ccc 和 aaa>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) 运行时。
【讨论】:
“它们之间覆盖了整个输入”很遗憾并非如此。一开始我也这么认为:( 你也假设常数时间算术,但当字符串超出字长时,这不太可能是可用的 我不假设恒定时间算术。我假设测试每个相等情况的 O(n) 成本。这涵盖了字符串到 int 的转换和算术成本。无论如何,我可能不会转换为 int 表示,而是在字符串域中进行数学运算。在摊销常数测试选项的情况下,我相信算术成本的增长与字符串到 int 的转换成本相同,即摊销常数。以上是关于给定一个数字,检查数字是不是形成一个加法方程?的主要内容,如果未能解决你的问题,请参考以下文章