【问题标题】:Finding Substring of Number with certain property查找具有特定属性的数字子串
【发布时间】:2014-07-28 00:37:53
【问题描述】:

我得到一个仅由 0 到 9 的数字组成的字符串。我想计算其中有多少子字符串是 2 的幂。

例如对于子串 2560616,子串 256 和 16 是 2 的幂。我需要计算任何给定子串中有多少这样的子串。

请注意,子字符串非常大,因此蛮力无法工作。所以我主要想解决2个问题

  1. 如何有效地计算所有 2 次方的子串
  2. 如何有效地计算子串是否是 2 的幂

我认为可能有 DP 方法,但我不确定。

【问题讨论】:

  • 你说的字符串有多长?它决定了最佳方法是什么。
  • @Coda17 字符串长度最大为 10^5
  • 除非你能想出一些花哨的数学算法,否则我认为你最好的选择是分支和修剪。困难在于尽早修剪。但是确保立即忽略任何以奇数结尾的字符串是一个开始。您还可以预先计算所有 2 的幂,以使将任何字符串与 2 的幂匹配只有 O(1) 时间复杂度。或者,您可以预先计算 2 的所有幂,然后使用正则表达式搜索您计算的数字的每一次出现。
  • 在您的示例中,子字符串“2”和“1”呢?
  • @NiklasB.是的,我忘了提。你能帮忙解决一下吗

标签: string algorithm dynamic-programming


【解决方案1】:

使用以下算法从 2 的幂的数字创建一棵树:

  1. 从代表空字符的根开始。
  2. 获取 2 的下一个幂,以相反的顺序获取其数字。
    1. 选择根。选择当前号码的最后一位。
    2. 转到与所选数字对应的所选节点的子节点。如果它尚不存在,请创建它。
    3. 选择当前号码的前一位。从 (2.) 重复直到没有更多的数字。
    4. 将当前节点标记为有效端点。
  3. 从 (2.) 重复直到位数 > 10^5

这棵树可能会占用几 GB 的内存。

现在你有了你的树。要计算 2 次方的子串数量,请执行以下操作:

  1. 从字符串末尾开始。
  2. 获取前一个字符。
    1. 选择树的根。
    2. 选择前一个字符(从外部 (2.) 中选择的字符开始)。
    3. 选择所选数字对应的所选节点的子节点。
    4. 如果选定的子节点被标记为有效端点,则将 count 加 1。
    5. 从 (2.) 开始重复,直到所选节点为空或到达字符串的第一个字符。
    6. 返回外部 (2.) 中选择的字符
  3. 选择前一个字符。从 (2.) 重复直到到达字符串的开头。

算法的描述不是“准备考试”,但我希望它可以理解。

【讨论】:

  • 所以基本上你建议在步骤 1 中用代表二的幂的字符串构建一个 trie。问题是构建这个 trie 将花费 Omega(n^2) 时间,这对于 n = 10^5 来说很慢。此外,在重叠字符串的情况下,您的搜索过程是错误的,这肯定发生在 2 的幂内(例如,1 是 1024 的前缀,2 是 32 的后缀)。你真正需要的是一个Aho-Corasick 自动机,它本质上就是你描述的trie,但带有后缀链接。
  • @NiklasB。 “问题是构建这个 trie 将花费 Omega(n^2) 时间,这对于 n = 10^5 来说很慢” - 确实如此,但您只需要构建一次。如果您只想搜索一行,可能有更好的方法,但如果您想多次应用搜索,您将很快收回投入构建树的时间。另请注意,如果您确实选择了 Aho-Corasick 自动机,您应该在字符串中倒退。这样你会得到一棵更小的树(2的幂可以从任何数字开始,但从后面的第n个数字是有限的)
  • @NiklasB。 “此外,如果字符串重叠,您的搜索过程是错误的” - 它不是。即使认为它不像 Aho-Corasick 自动机那么复杂,但它通过步骤 (6) 解决了重叠字符串问题。
  • 无论如何,O(n^2) 很容易实现,只需对每个 2 的幂进行简单的线性时间模式搜索即可。不需要 trie 或任何东西(而且也只有 O(n) 额外空间。看看是否有 o(n^2) 方法会很有趣。
  • @NiklasB。在 O(n^2) 中构建树与使用它进行线性搜索和以 O(n^2) 复杂度运行每个搜索之间存在差异(假设您要搜索超过 1 个序列)
猜你喜欢
  • 1970-01-01
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
相关资源
最近更新 更多