从字符串列表中查找相同子字符串的算法

时间:2015-01-14 15:04:09

标签: algorithm string-matching

我在这里有点失落,欢迎一些帮助。我们的想法是从字符串列表中找到匹配的子字符串。它不一定是完美的。让我们用一个例子解释一下:

“COUNTRY_NAME” “COUNTRY_ID” “Rankcountry” “ThisWillNotMatch”

将返回“country”

它必须是有效的东西,因为“蛮力”算法看起来有点可怕。

3 个答案:

答案 0 :(得分:1)

不确定它是否有效"或者被认为是暴力......我把它留给别人来判断。

  1. input =字符串列表
  2. 为输入中的每个s执行:computeAllStrides(string - > string list)(参见下面的代码)
  3. 使用string类型的键创建空的可变字典,类型为int
  4. 所有步幅=步骤2中的字符串列表 - >更新字典 当字典中存在跨步时更新字典(步幅) - >增加各自进入的价值 当字典中不存在步幅时更新字典(步幅) - >将(stride,1)添加到Dictionary
  5. 查找字典条目,该条目产生stride.Length * frequency
  6. 的最大值
  7. 报告发现最大值。
  8. 如果不区分大小写,请先对每个输入字符串执行toLowercase操作。

    open System.Collections.Generic
    
    let input = ["Country_Name"; "Country_id"; "RankCountry"; "ThisWillNotMatch"; ]
    
    let rec getAllStrides text =
      let length = String.length text
      match length with
        | 0 -> []
        | 1 -> [text]
        | _ -> [ for i = 1 to length do yield text.Substring(0, i ) ] @ getAllStrides (text.Substring(1))
    
    
    type HashTable = System.Collections.Generic.Dictionary<string,int>
    
    let update (ht : HashTable) strides =
      List.iter (fun s ->
                 if ht.ContainsKey(s) then ht.[s] <- ht.[s] + 1 else ht.Add( s, 1 )
                 ) strides
    
    let computeStrideFrequencies input =
      let ht = new HashTable()
      input |> List.iter (fun i -> update ht (getAllStrides i) )
      ht
    
    
    let solve input =
      let theBest = input |> computeStrideFrequencies |> Seq.maxBy (fun (KeyValue(k,v)) -> k.Length * v)
      theBest.Key
    

    解决输入;;    val it:string =&#34; Country&#34;

答案 1 :(得分:1)

受到Dobb博士的Jon Bentley's "Algorithm Alley"专栏的启发。

构建每个后缀的索引。对索引进行排序会将常见的子字符串组合在一起。走分类索引比较相邻的子串,你可以很容易地找到最长的(或最常见的)。

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <string>
#include <vector>

std::size_t LengthInCommon(const char *left, const char *right) {
  std::size_t length_of_match = 0;
  while (*left == *right && *left != '\0') {
    ++length_of_match;
    ++left;
    ++right;
  }
  return length_of_match;
}

std::string FindLongestMatchingSubstring(const std::vector<std::string> &strings) {
  // Build an index with a pointer to each possible suffix in the array.  O(n)
  std::vector<const char *> index;
  for (const auto &s : strings) {
    for (const auto &suffix : s) {
      index.push_back(&suffix);
    }
  }

  // Sort the index using the underlying substrings.  O(n log_2 n)
  std::sort(index.begin(), index.end(), [](const char *left, const char *right) {
    return std::strcmp(left, right) < 0;
  });

  // Common strings will now be adjacent to each other in the index.
  // Walk the index to find the longest matching substring.
  // O(n * m) where m is average matching length of two adjacent strings.
  std::size_t length_of_longest_match = 0;
  std::string match;
  for (std::size_t i = 1; i < index.size(); ++i) {
    const char *left = index[i - 1];
    const char *right = index[i];
    std::size_t length_of_match = LengthInCommon(left, right);
    if (length_of_longest_match < length_of_match) {
      length_of_longest_match = length_of_match;
      match.assign(index[i], index[i] + length_of_longest_match);
    }
  }

  return match;
}

int main () {
  std::vector<std::string> strings;
  strings.push_back("Country_Name");
  strings.push_back("Country_id");
  strings.push_back("RankCountry");
  strings.push_back("ThisWillNotMatch");
  std::cout << FindLongestMatchingSubstring(strings) << std::endl;
  return 0;
}

打印:

Country_

答案 2 :(得分:0)

我仍然不明白为什么&#34; c&#34;不能回答。我想你更喜欢更长的琴弦。需要直接获得优化功能!

无论如何,您可以使用Tries解决此问题。为每个字符串创建一个Trie。为每个节点计数1。并通过总结计数来合并所有尝试。通过这种方式,您可以获得所有子字符串及其计数。现在,使用您的优化函数来选择最佳函数。