快速找到一个不在给定字符串中的子字符串的短字符串

时间:2014-04-11 00:32:09

标签: regex string perl substring

我一直在尝试使用分隔符序列化一些数据并遇到问题。

如果它包含一个分隔符,我希望能够快速找到一个不是给定字符串的子字符串的字符串,这样我就可以将它用作分隔符。

如果我不关心大小,找到它的最快方法是检查给定字符串中的字符,并选择一个不同的字符,制作给定字符串长度仅为该字符的字符串。

可能有办法进行某种检查,首先测试中间字符,然后测试第一段和最后一段的中间...但我没有看到明确的算法。

我目前的想法,相当快,但不是最佳的 初始化一个散列,所有字符都作为键,0作为计数 使用哈希计算字符串字符作为字节。

找到最少数量的字符。如果我找到一个零字符的话,立即停止。

使用该字符数加1作为分隔符。

我相信那是O(n),虽然显然不是最短的。但是分隔符总是不会超过n / 256 + 1个字符。

我也可以尝试某种基于trie的构造,但是我不太确定如何实现它,那0(n ^ 2)对吗?

https://cs.stackexchange.com/questions/21896/algorithm-request-shortest-non-existing-substring-over-given-alphabet

可能会有帮助。

2 个答案:

答案 0 :(得分:1)

你的字符计数方法是不够的,因为你只是在谈论当前的字符串。分隔符的重点在于理论上你将多个字符串分开,因此你需要统计所有字符串。

我看到两种可能的替代解决方案

  1. 选择一个分隔符并转义字符串中的分隔符。

    可以使用URI::Escape来转义特定字符,例如&,并将其用作分隔符。

  2. 在发送字符串之前指定字符串的大小。这样你就可以确切地知道要拉多少个字符。基本上是packunpack

  3. 因为我已经在替代解决方案的列车上,不妨提出所有其他序列化模块:Comparison of Perl serialization modules

    我喜欢像这样的任务背后的理论,但是像XY Problem

    那样响起来

答案 1 :(得分:1)

我同意@Miller,你最好的选择是挑选一个角色并在文中逃避。

但是,这不是你问的,所以我会试着回答这个问题。

我认为这些字符串很长,所以找到分隔符是时间敏感的。

在直接的Perl中,哈希的想法可能会尽可能快。作为本机C扩展,您可以做得更好。我说这是因为我的经验是Perl数组访问由于某种原因很慢,而且这个算法使用数组效果很好:

int n_used_chars = 0;
int chars[256], loc_of_char[256];
for (int i = 0; i < 256; i++) used_chars[i] = loc_of_char[i] = i;

for (int i = 0; i < string_length; i++) {
  char c = string[i];
  int loc = loc_of_char[c];
  if (loc >= n_used_chars) {
    // Character c has not been used before. Swap it down to the used set.
    chars[loc] = chars[n_used_chars];
    loc_of_char[chars[loc]] = loc;
    chars[n_used_chars] = c;
    loc_of_chars[c] = n_used_chars++;
  }
}
// At this point chars[0..n_used_chars - 1] contains all the used chars.
// and chars[n_used_chars..255] contains the unused ones!

这将是O(n)并且在实践中非常快。

如果使用了所有字符怎么办?然后事情变得有趣......有64K双字节组合。我们可以使用上面的技巧,两个数组都是64K。初始化和内存将是昂贵的。这值得吗?也许不是。

如果使用了所有字符,我会使用随机方法:猜一个分隔符,然后扫描字符串以验证它没有被包含。

如何以谨慎的方式进行猜测?