【问题标题】:Efficiently remove strings that are contained within other strings in LinkedList有效删除 LinkedList 中其他字符串中包含的字符串
【发布时间】:2017-06-06 10:11:06
【问题描述】:

我有一个包含字符串的简单 LinkedList。

LinkedList<String> list = new LinkedList<String>();
list.add("A, B, C, D");
list.add("R");
list.add("A");
list.add("C, D");

所以,我们的 LinkedList 是:[ "A, B, C, D", "R", "A" ,"C, D" ]

如您所见,"A""C, D" 已包含在 "A,B,C,D" 中。

删除包含的字符串最有效的方法是什么?

【问题讨论】:

  • 为什么不使用Set
  • Set 不起作用,对于那种逻辑你应该编写自己的实现。
  • 您的数据结构不适合此目的。考虑将值存储为 Set 而不是 CSV 字符串。
  • 为什么要将逗号分隔的字符串存储在列表中。你用这些做什么,这使它成为最好的代表?
  • 究竟应该是什么结果? "C, D" 应该被省略吗? 是否可以将字符串 "A, B, C, D" 改为 "A, B"?最后但并非最不重要的一点:当应该添加 "R, X" 时会发生什么(R 已经存在,但不是 X)?

标签: java string linked-list


【解决方案1】:

将 csv 格式的字符串转换为字符串值。然后将它们存储为集合元素。如果方法add()返回true,则表示值已经存在。

String[] values = csvStr1.split(",");
Set<String> hashSet = new HashSet<String>(Arrays.asList(values));

String[] values2 = csvStr2.split(",");
for (String value: values2 ) {
    if( hashSet.add(value) == true ) {
          //value already present. Ignore this or do whatever you want.
    }
} 

【讨论】:

    【解决方案2】:

    首先,您可以在添加新值之前使用 contains() 方法(只要您每次都添加单个字符串,但您不是......)。

    其次,如果您更改添加字符串的方式或 LinkedList 限制,似乎可以轻松避免这个“问题”..

    无论如何,这是一个可能适合您需要的简单方法:

    private  void deleteIfContains(LinkedList<String> list, String str) {
        Iterator<String> headIterator = list.iterator();
        HashMap<Integer, String> newValues = new HashMap<>();
        int index = 0;
    
        while (headIterator.hasNext()) {
            String headString = headIterator.next();
    
            if (headString.contains(str)) {
                headIterator.remove();
                //replace method won't handle ','..you will need to use regex for it
                newValues.put(index, headString.replace(str, ""));
            }
            index++;
        }
    
        //Avoid ConcurrentModificationException
        for (int i : newValues.keySet()) {
            list.add(i, newValues.get(i));
        }
    }
    

    【讨论】:

      【解决方案3】:

      正如@nikowis 所说,最佳解决方案取决于问题定义。

      如果值是元素“A”、“B”、“C”、“D”……更有效的解决方案(在计算时间上)可以将列表转换为列表>或单个设置。

      如果值是“子字符串”,例如“C, E”是一个值(而不是两个“C”和“E”),您可以使用子字符串“Trie”(https://en.wikipedia.org/wiki/Trie)。它可以非常快速地找到 trie 中是否存在子字符串(O(log N),其中 N 是要添加的字符串的长度)。

      【讨论】:

        【解决方案4】:

        我建议您改用Set,但您必须将每个字母都包含在一个String 变量中(也许您应该使用Character?)。

        如果您真的想坚持自己的想法,请考虑实施您自己的Set。但首先要弄清楚在这种情况下会发生什么:

        LinkedList<String> list = new LinkedList<String>();
        list.add("A, B, C, D");
        list.add("C, E");
        

        C 应该被拒绝,但 E 呢?

        【讨论】:

        • 您评论说Set 不起作用并继续回答使用Set 的问题;)
        • 任何现有的集合实现都不起作用,正如我在评论中所说的自定义实现可以处理该逻辑。
        • 你说,我建议你使用 Set 来代替,然后你说如果你真的想坚持自己的想法。你基本上是说使用Set 对吗?
        • 但你会...
        • 对于没有经验的程序员来说,我的思维捷径可能不太清楚。我可以向你保证,我不是一个没有经验的程序员。请注意,您不需要 Set 的自定义实现。一个基本的货架Set 就可以了。
        猜你喜欢
        • 2015-10-20
        • 2013-09-09
        • 1970-01-01
        • 2020-02-14
        • 2014-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-30
        相关资源
        最近更新 更多