【问题标题】:Optimally searching a substring within a string java以最佳方式在字符串 java 中搜索子字符串
【发布时间】:2018-02-04 19:56:05
【问题描述】:

我有一个电话号码列表,其中可能包含也可能不包含国家/地区代码。我从始终包含国家/地区代码的后端服务中获得一个号码。所以我已经最佳地找到了与该号码匹配的号码来自后端服务。

现在我正在做的是:

for(String number : backendNumbers){
    for(Map.Entry<String, String> entry : contactMap.entrySet()){
        if(number.endsWith(entry.getKey()) && entry.getKey().length() > MINIMUM_CONTACT_LENGTH){
            Log.i(TAG, "Found name for "+entry.getKey()+" : "+entry.getKey()+":"+entry.getValue());
            break;
        }
    }
}

其中联系人地图是这样的联系人地图 = -> 此键可能包含也可能不包含国家代码。在大多数情况下,它们不会。

当我从后端获得一个始终包含如下国家代码的号码时:“+8801710111111”。

现在这种方法的问题是每次我需要该地图时都会产生生成联系人地图的开销。同样,在我从后端为每个号码获取 N 个号码的情况下,我需要遍历整个联系人地图才能找到一个名字。

那么我可以在这里做得更好吗?任何建议将不胜感激。

【问题讨论】:

    标签: java android search optimization substring


    【解决方案1】:

    假设两个集合都很大,以下可能会增加 10 倍:

    for (char c='0'; c<='9'; ++c) {
        Map<String, String> submap = new Map<>();
        for(Map.Entry<String, String> entry : contactMap.entrySet()) {
            String key = entry.getKey();
            if (key.length() > MINIMUM_CONTACT_LENGTH
                  && key.charAt(key.length() - 1) == c) {
              submap.put(key, entry.getValue());
            }
        }
        for(String number : backendNumbers){
            if (!number.isEmpty()
                     && number.charAt(number.length() - 1) == c) {
                for(Map.Entry<String, String> entry : submap.entrySet()) {
                     .... do what you did
                }
            }
        }
    }
    

    这个想法很简单:一个字符串只能是另一个字符串的子字符串,如果两者都以相同的字符结尾。所以我相应地拆分了两个集合并保存了我的测试,比如 xxxxx1 和 xxxxx2。

    显然,您可以改用最后两位数字,但这会增加更多开销。原始复杂度是O(m*n),使用这个技巧是O((m+n)*k + (m/k)*(n/k)),其中k 是桶的数量。我假设最后一个数字是均匀分布的,通常是这样。

    本可以做得更好......

    【讨论】:

      【解决方案2】:

      您可以创建一个包含和不包含国家/地区代码的后端号码的地图(不是总是 3 个字符吗?)

      Map<String,String> backendMap = new HashMap<>();
      for(String number : backendNumbers){
          backendMap.put(number,number);
          backendMap.put(number.substring(3),number);
      }
      

      然后您可以简单地在 backendMap 上查找(或不查找)该号码(假设该号码的国家代码始终采用相同的形式)。

      【讨论】:

      • 不,遗憾的是,国家代码并不总是 3 个字符。它可以是 1、2、3 或 4 个字符。
      【解决方案3】:

      现在这种方法的问题是每次我需要该地图时都会产生生成联系人地图的开销。

      好吧,要么你有一些结构来促进搜索,要么你搜索整个列表。

      我会创建一个Map&lt;String, String&gt; 来命名。创建地图时还要计算minLength的数字的最小长度。

      然后,给定一个后端编号,不仅要查找该编号,还要查找长度为 minLength 的所有后缀。

      for (int beginIndex = 0; beginIndex <= (backendNumber.length() - minLength); beginIndex++) {
          String name = nameByNumber.get(backendNumber.substring(beginIndex));
          if (name != null) {
              return name;
          }
      }
      

      这将为您提供类似于 O(后端数字的最大长度 - 数字的最小长度)的复杂度。

      【讨论】:

        【解决方案4】:

        对于给定的循环代码,您可以转移到map.keySet() 以仅处理字符串键。 否则这种方法并没有错,尤其是在比较 hashmap 的值时,这是您需要的最小开销。

        【讨论】:

          猜你喜欢
          • 2016-04-21
          • 1970-01-01
          • 1970-01-01
          • 2015-03-20
          • 2019-10-06
          • 2012-04-10
          • 1970-01-01
          • 2012-12-18
          相关资源
          最近更新 更多