【问题标题】:Creating a dictionary: Method to prevent the same word from being added more than once创建字典:防止同一个词被多次添加的方法
【发布时间】:2016-01-23 16:22:55
【问题描述】:

我需要创建一个方法来确定我尝试添加到我的 String[] 字典中的单词是否已经被添加。我们不允许在这个项目中使用 ArrayList,只能使用数组。

我是从这个开始的

public static boolean dictHasWord(String str){
    for(int i = 0; i < dictionary.length; i++){
       if(str.equals(dictionary[i])){
           return true;
       }
    }
    return false;
}

但是,我的教授告诉我不要使用这个,因为它是一个线性函数 O(n),并且无效。我还有什么办法可以解决这个问题?

【问题讨论】:

  • 您了解了哪些数据结构可能允许您使用?有几个显而易见的答案,但如果它们涉及到你一直在学习的数据结构,那么这是一个测试,以确保你已经学会了它,我很犹豫给你答案;如果您还没有了解它们,那么期望您自己弄清楚它们就太过分了。如果不知道真正的限制和上下文的其余部分,很难回答这样的问题。
  • 我们只能使用字符串数组来创建字典。没有 ArrayList 或类似的东西。唯一的其他限制是我们不能调用 Arrays.sort() 或 Arrays.binarySearch()。
  • 我们正在从 3 个包含完整书籍的单独文本文件中读取单词,然后创建一个 String[] 字典,我们最终将对其进行排序并放入它自己的文件 dictionary.txt。我们的字典中不能两次添加同一个单词,单词的长度必须> 1,并且单词不能以大写字母开头。我只需要使这种方法更有效地工作。它与我以前拥有的东西一起工作。
  • 根据连续字符搜索单词。您只需将第一个字母开头的字典条目作为新词进行比较。这大大减少了搜索/比较时间。

标签: java arrays string dictionary


【解决方案1】:

虽然在这种情况下它可能有点矫枉过正,但哈希表不会是 O(n)。

这利用了这样一个事实,即每个字符串都可以通过hashCode() 转换为 int,并且相等的字符串将产生相同的哈希。

我们的字典可以声明为:

LinkedList<String>[] dictionary;

换句话说,每个位置可能存在多个字符串,这是由于可能的冲突(不同的字符串产生相同的结果)。

最简单的加法解决方案是:

public void add(String str)
{
  dictionary[str.hashCode()].add(str);
}

但为了做到这一点,您需要使数组大小等于 1 减去 hashCode() 函数的最大值。这对你来说可能是太多的记忆。所以我们可以做一些不同的事情:

public void add(String str)
{
  dictionary[str.hashCode()%dictionary.length].add(str);
}

这样我们总是修改散列。为获得最佳结果,您应该将字典大小设置为某个素数,或者至少是单个素数的幂。

然后,当您想测试字符串的存在时,您完全按照原来的方式进行操作,但您使用的是从哈希中获得的特定 LinkedList

public static boolean dictHasWord(String str)
{
    for(String existing : dictionary[str.hashCode()%dictionary.length])
    {
       if(str.equals(existing)){
           return true;
       }
    }
    return false;
}

这时你可能会问“这不是 O(n) 吗?”。答案是它不是,因为散列函数没有考虑数组中元素的数量。分配给数组的内存越多,冲突就越少,这种方法越趋向于 O(1)。


如果有人找到这个答案是为了寻找真正的解决方案(不是家庭作业)。然后只需使用HashMap

【讨论】:

    【解决方案2】:

    如果您被允许使用Arrays 类作为分配的一部分,您可以对数组进行排序并改用二分查找,这不是 O(n)。

    public static boolean dictHasWord(String str){
      if(Arrays.binarySearch(dictionary, str) != -1){
         return true;
      }
    
      return false;
    }
    

    请记住,您必须先排序。

    编辑:
    关于编写您自己的实现,这里有一个sample 来帮助您。这里也是javadocs for compareTo()。这里another sample(基于 int 的示例)显示了递归和非递归之间的区别,特别是在 Java 中。

    【讨论】:

    • 是的,我们可以使用数组类,但是我们不能调用 Arrays.sort 或使用它的搜索方法
    • 我们必须创建自己的排序方法,然后在添加每个单词后立即调用我们的排序方法。
    • 根据您上面的评论,除了实际的搜索方法之外,您似乎拥有所需的一切,但您无法使用已经提供的方法。为什么不实现自己的? vogella.com/tutorials/JavaAlgorithmsSearch/…
    • 好了,我们学习了binarySearch。我了解您刚刚发布的链接,但是,现在我正在搜索字符串是否已添加。我将如何使用字符串而不是整数来实现二进制搜索。
    • 添加了一个示例。有一些与代码质量和算法工作原理相关的 cmets 也很有用。还包括 .compareTo 的 Javadoc,因为在这种情况下了解所有这些如何组合在一起很重要。
    【解决方案3】:

    这是一个如何快速搜索具有良好可读性的数组的示例。我建议使用这种方法来搜索你的数组。

    import java.util.*;
    
    public class test {
    
    public static void main(String[] args) {
        String[] list = {"name", "ryan"
        };
        //returns boolean here
        System.out.println(Arrays.asList(list).contains("ryan"));
        }
    }
    

    【讨论】:

    • 这仍然是一个 O(n) 解决方案。
    • 定义 O(n) 解决方案?这是线性搜索的另一个术语吗?
    • 如果您不寻找线性,我会研究一种递归方式进行排序
    • O(n) 表示它运行的时间与“n”成正比。线性搜索是 O(n) 算法的一个示例。 contains() 上的 contains() 方法是线性搜索。
    • 当我在我的方法中使用 for 循环时,如果是最坏的情况,我将不得不搜索数组中的每个元素。因此它的大符号是 O(n)。
    猜你喜欢
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    相关资源
    最近更新 更多