【问题标题】:How to locate simple words amongst compound/simple words using Java?如何使用 Java 在复合词/简单词中定位简单词?
【发布时间】:2016-11-12 00:00:27
【问题描述】:

我有一个单词列表,其中包含“简单”和“复合”单词,并且想要实现一个算法,该算法可以打印出一个单词列表,其中不包含由简单单词组成的复合词。

样本输入:

chat, ever, snapchat, snap, salesperson, per, person, sales, son, whatsoever, what, so

期望的输出:

chat, ever, snap, per, sales, son, what, so

我已经写了以下内容,但我不知道如何从这里开始:

private static String[] find(String[] words) {

    ArrayList<String> alist = new ArrayList<String>();
    Set<String> r1 = new HashSet<String>();
    for(String s: words){
        alist.add(s);
    }
    Collections.sort(alist,new Comparator<String>() {

        public int compare(String o1, String o2) {

            return o1.length()-o2.length();
        }
    });

    int count= 0;
    for(int i=0;i<alist.size();i++){
        String check = alist.get(i);
        r1.add(check);
        for(int j=i+1;j<alist.size();j++){

            String temp = alist.get(j);
            //System.out.println(check+" "+temp);
            if(temp.contains(check) ){

                alist.remove(temp);

            }
        }
    }
    System.out.println(r1.toString());
    String res[] = new String[r1.size()];
    for(String i:words){
        if(r1.contains(i)){
            res[count++] = i;
        }
    }

    return res;
}

任何关于更好方法的指导/见解或建议将不胜感激。

【问题讨论】:

标签: java algorithm trie


【解决方案1】:

我试图检查您的代码,看起来“儿子”不在您的输出中。我相信它因为这条线而失败了:

if(temp.contains(check)) { <-- wrong check.
    alist.remove(temp); 
}

因此,您应该有一个小循环来执行以下操作,而不是简单地检查 temp.contains(check):

  1. temp 是否以check 开头?
  2. 如果 1) 通过了,那么让 temp = temp.substring(check.length),然后再回到 1),直到 temp == "";

另一种实现是设置一个 trie (https://en.wikipedia.org/wiki/Trie) 并使用它进行检查?

  1. 根据单词长度对单词列表进行排序
  2. foreach 单词,如果单词不在trie 中,则将其添加到trie。否则,这要么是一个重复词,要么是一个复合词
  3. 使用 DFS 将 trie 输出到单词列表中。

第 1 步确保当你检查复合词时,它的简单词已经在 trie 中。

【讨论】:

    【解决方案2】:

    我没有尝试在您的代码中查找错误,而是使用简单的循环和递归辅助方法编写了自己的 impl:

    private static String[] find(String[] array) {
        Set<String> words = new LinkedHashSet<>(Arrays.asList(array));
        Set<String> otherWords = new HashSet<>(words);
        for (Iterator<String> i = words.iterator(); i.hasNext(); ) {
            String next = i.next();
            otherWords.remove(next);
            if (isCompound(next, otherWords)) {
                i.remove();
            } else {
                otherWords.add(next);
            }
        }
        return words.stream().toArray(String[]::new);
    }
    
    private static boolean isCompound(String string, Set<String> otherWords) {
        if (otherWords.contains(string)) {
            return true;
        }
        for (String word : otherWords) {
            if (string.startsWith(word)) {
                return isCompound(string.replaceAll("^" + word, ""), otherWords);
            }
            if (string.endsWith(word)) {
                return isCompound(string.replaceAll(word + "$", ""), otherWords);
            }
        }
        return false;
    }
    

    live demo

    这会产生您想要的输出,这需要保留词序。

    说明

    复合词仅由列表中的其他词组成。重要的是,这意味着复合词 startend 与其他词。我们可以利用这个事实只检查 start/end ,而不是在一个单词的每个位置都搜索其他单词,这大大简化了代码。

    因此:对于列表中的每个单词,如果它以 another 单词开头/结尾,则删除该单词并重复该过程,直到没有任何内容为止,此时您知道该单词是复合词。

    一组“其他词”,即移除当前词的完整集合,被传递给辅助方法以进一步简化代码。

    【讨论】:

    • ♦ 抱歉,您介意为实现添加一些解释/cmets 吗?努力学习。谢谢你,之后会接受/投票。
    • @JoKo 这个解释够吗?
    • ♦ 不知道我是怎么错过的。非常感谢输入,我尝试了一下,但实际上给出了不同的输出。它对你有用吗?
    • @joko 是的,它有效。有一个缺少的 return 语句,我已修复,我添加了一个 link to live demo,这表明它可以正常工作。
    • ♦ 谢谢!需要一些澄清。但是 for 循环中的 Iterator&lt;String&gt; i = words.iterator(); i.hasNext(); 是什么? "^""$" 是什么意思?如果您可以为每一行提供简短的注释 sn-ps 将非常有帮助并清除很多事情。提前谢谢你
    【解决方案3】:

    这是我直接的 n^2 解决方案:

    static String[] simpleWords(String[] words) {
        String[] result;
        HashSet<Integer> map = new HashSet<>();
        for(int i = 0; i < words.length; i++) {
            String word = words[i];
            for(int j = 0; j < words.length; j++) {
                if(j != i) {
                    word = word.replaceAll(words[j], "");
                }
            }
            if(!word.equals("")) {
                map.add(i);
            }
        }
        result = new String[map.size()];
        int i = 0;
        for(int index: map) {
            result[i] = words[index];
            i++;
        }
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-18
      相关资源
      最近更新 更多