【问题标题】:Check if strings in a list can be formed by concatenation of elements in the same list检查列表中的字符串是否可以通过连接同一列表中的元素来形成
【发布时间】:2020-03-04 16:08:33
【问题描述】:

检查列表中的字符串是否可以由同一列表中的元素串联形成

例如:

输入列表 -

{ best,  rockstar,   star,  guide,  bestguide, rock }

输出:-

rockstar -> rock, star

bestguide -> best, guide

这里的“摇滚明星”可以用摇滚和明星组成。类似地,“bestguide”可以通过连接“best”和“guide”来形成。

到目前为止我的解决方案-通过相互连接来创建所有字符串组合(2 个字符串在一起,3 个字符串在一起等等)并存储在地图中。

地图结构如下

Map<String, List<String>>

{rockstar : [rock, star], ....}

现在检查只是遍历原始列表并检查地图。如果找到它,那么它是一种可能的解决方案。

寻找具有更好时间/空间复杂度的更好解决方案

【问题讨论】:

  • 列表大小是多少?
  • 它可能非常大。您可以考虑 1
  • 你肯定需要一个递归解决方案。
  • 您需要所有解决方案还是只需要第一个?
  • 全部解法,2串、3串、4串等。

标签: java arrays string algorithm


【解决方案1】:

我认为一种标准方法可能是从字典中构造一个 trie。然后对于每个候选者,遍历特里树,当匹配路径到达末尾(标记一个较小的单词)时,再次从特里树的顶部继续使用候选者的剩余后缀。如果存在类似的匹配,我们可能需要对每个候选人进行几次回溯试验;但是在只有 10,000 个的字典中,除非数据是退化的,否则这些平均应该很少。

【讨论】:

    【解决方案2】:

    首先,对不起我的英语不好。 我有一个幼稚的方法,你应该试试:

    步骤1:按元素长度降序对列表进行排序

    第二步:依次(从排序列表的左到右),按照以下规则将元素一个接一个地添加到树中:

    • 树的每个节点都包含一个字符串,树的根不包含任何内容

    • 每个父节点中的字符串都包含其子节点中的字符串。

    • 第 3 步:获取结果:如果节点中的字符串长度等于子节点中字符串长度的总和,那么我们将获得所需的结果。

    【讨论】:

      【解决方案3】:

      这是蛮力方法。我们可以首先形成一个原始术语的列表,然后对该列表进行两次迭代以生成所有组合可能性。对于也已包含在原始列表中的每个组合,我们将该组合打印到控制台。

      String[] terms = new String[] { "best",  "rockstar",   "star",  "guide",  "bestguide", "rock" };
      List<String> list = Arrays.asList(terms);
      Set<String> set = new HashSet<String>(list);
      for (int i=0; i < list.size()-1; ++i) {
          for (int j=i+1; j < list.size(); ++j) {
              if (set.contains(list.get(i) + list.get(j))) {
                  System.out.println(list.get(i) + list.get(j) + " -> " + list.get(i) + ", " + list.get(j));
              }
              if (set.contains(list.get(j) + list.get(i))) {
                  System.out.println(list.get(j) + list.get(i) + " -> " + list.get(j) + ", " + list.get(i));
              }
          }
      }
      

      打印出来:

      bestguide -> best, guide
      rockstar -> rock, star
      

      【讨论】:

      • 感谢您的解决方案。然而,这个解决方案是 O(n* n * n)。您正在使用两个循环 (O(n* n) ),然后在另一个 O(n) 的列表中搜索,因此总共为 O(n* n* n)。我建议的解决方案是 O(n* n)。
      • @nagendra547 并且代码仅检查字符串是否可以由其他两个组成,不考虑三元组。
      • @nagendra547 然后使用HashSet 查找每个可能的匹配项。这样可以避免搜索列表,但可能会使用更多的存储空间。
      • @nagendra547 您的解决方案将具有 O(2^n) 复杂性,而不是 O(n^2),因为您说过,“通过相互连接来创建所有字符串组合(2 个字符串在一起, 3 串在一起等等)。”
      • @TimBiegeleisen 是的。这是公平的理由。 HashSet 解决方案变得和我的类似
      【解决方案4】:
      1. 使用 AC 自动化并将集合中的所有字符串添加到其中。

      2. 将集合中的所有字符串与自动化和记录匹配点匹配。

      3. 使用动态规划连接匹配点。

      最坏情况时间复杂度:O(n*(长度之和))

      n 来自多个长度选项,由 DP 过程决定。想象一个字符串集合 {a, aa, aaa, aaaa, ..., a^n}。

      在这里了解空调自动化:link

      【讨论】:

      • 为什么没有人评论我的回答? :(
      • 讨论蛮力方法并假设数据集完全符合您的意愿是没有意义的。
      【解决方案5】:

      这是一个子集和问题。 标准解决方案是动态规划,但通常你会找到整数的解决方案:Subset Sum algorithm

      在这里改编会给出类似的结果:

      static List<String> substrings(String s) {
          List<String> l = new ArrayList<String>();
          for(int end=1; end < s.length()+1; ++end) {
              for(int start=0; start < end; ++start) {
                  l.add(s.substring(start, end));
              }
          }
          return l;
      }
      
      static boolean isInConcatenations(String target, List<String> list) {
          Set<String> set = new HashSet<String>();
          List<String> ss = substrings(target);
          set.add("");
          for (String s: list) {
              if (s == target) continue; // do not use directly 'target' if it's in the list
              Set<String> prev = Set.copyOf(set);
              for (String sub: ss) {
                  if ((sub.startsWith(s) && prev.contains(sub.substring(s.length(), sub.length()))) ||
                      (sub.endsWith(s) && prev.contains(sub.substring(0, sub.length()-s.length()))) ) {
                      set.add(sub);
                  }
              }
          }
          return set.contains(target);
      }
      

      这里substrings(s) 返回字符串的所有非空子字符串的List

      复杂度大概是length(list) * length(target)**2

      【讨论】:

        【解决方案6】:

        感谢分享这个有趣的练习。

        使用 Java 8+ 和 Streams,这是迭代列表和处理小型或大型数据集的最佳方法。

        请记住,您可以使用该方法:

        • inputList.stream() 的列表来蒸汽列表
        • inputList.parallelStream() 如果您的列表不包含同步对象并且不调用任何同步方法(不允许并行)。

        这里有一篇关于 DZone 的好帖子,用于了解 Stream API 的性能 https://dzone.com/articles/java-performance-for-looping-vs-streaming

                    final String input = "best,rockstar,star,guide,bestguide,rock,fake,rockfaller";
        
                // Start to finding input pairs
                List<String> inputList = Arrays.asList(input.split(","));
                List<String> combi = inputList.stream()
                        .filter(s -> input.contains(s) && input.lastIndexOf(s) != input.indexOf(s))
                        .collect(Collectors.toList());
        
                // Build ouput
                final HashMap<String, List<String>> output = new HashMap<>();
                inputList.stream()
                        // Remove pair words 
                        .filter(s -> !combi.contains(s)) 
                        .filter(s -> combi.stream().anyMatch(pair -> s.startsWith(pair) || s.endsWith(pair)) )
                        .forEach( s -> {
                            List<String> result = combi.stream()
                                    .filter(pair -> s.startsWith(pair) || s.endsWith(pair))
                                    // Sort the output result
                                    .sorted((s1, s2) ->  s.startsWith(s1) ? 0 : 1)
                                    .collect(Collectors.toList());
                            Collections.sort(result);
        
                            if(result.size() > 1)
                            {
                                output.put(s, result);
                            }
                        });
        
                System.out.println(output);
        

        这是打印 HashMap 结果时的输出

        {bestguide=[最佳,指南],rockstar=[摇滚,明星]}

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-27
          • 1970-01-01
          • 2012-02-21
          • 2010-10-04
          • 2012-08-30
          • 2018-02-12
          • 2015-10-03
          • 2017-11-20
          相关资源
          最近更新 更多