【问题标题】:How to compare character input by user to dictionary file in Java?如何将用户输入的字符与Java中的字典文件进行比较?
【发布时间】:2017-04-05 19:02:00
【问题描述】:

我需要读取用户输入并将其与dictionary.txt. 进行比较。用户可以输入任意数量的字符,并且程序必须返回可以由这些字符组成的所有英文单词。这些字母可以按任何顺序使用,并且只能使用一次。 例如:

用户输入:“odg”

输出: "dog" , "god" ... 和任何其他

经过大量研究,我想出了以下部分解决方案:

  1. 读取用户输入
  2. 转换为字符数组
  3. 根据数组长度循环遍历文档
  4. 使用 indexOf 将该数组中的每个字符与每一行进行比较,然后打印不返回 -1 的单词/s

如何将用户输入的一组字符与文本文件(字典)中的字符进行比较?字符不必按任何顺序匹配。(如上面使用的示例所示)

请耐心等待,我知道这一定是完成此类任务的最低效的方法之一!任何关于如何实现我的原始想法的进一步想法将不胜感激,同时我也愿意接受任何新的和更有效的方法来执行此操作。

以下是我到目前为止的想法:

  public static void main(String[] args) throws FileNotFoundException {
    BufferedReader reader1 = new BufferedReader(new FileReader(FILENAME));
    Scanner sc = new Scanner(System.in);
    String line;
    ArrayList<String> match = new ArrayList<>();

    System.out.println("Enter characters to see which english words match: ");
    String userInput = sc.next();

    char arr[]  = userInput.toCharArray();
    int i;

        try {

            while ((line = reader1.readLine()) != null) {

                for (i=0; i < arr.length; i++)
                {
                   if ((line.indexOf(userInput.charAt(i)) != -1) && (line.length() == arr.length)) {
                       match.add(line);
                    }
                    else {
                //        System.out.println("no matches");
                    }
                }

            }
            System.out.println(match);
        }

    catch (IOException e) {

        e.printStackTrace();

    }

**当前结果:**

文本文件中的单词:

cab
dog
god
back
dogs
quick

用户输入:“odg”

程序输出:

[god, god, god, dog, dog, dog]

程序应该返回字典中可以由用户输入的字符串组成的所有单词在这种情况下,我设法返回两个实例,但是,每个实例都显示了 3 次(arr.length)。

【问题讨论】:

  • 您的问题是什么?您的代码有什么具体问题? 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。
  • 您的问题是“如何检查是否可以从其他单词中的字符创建单词”?如果是,请查看Check if letters that a word consists of are present in another string
  • 无论如何,您应该尝试在代码中分离特定任务。例如,您可以创建方法boolean test(characters, word),您将在其中进行验证。如果结果为真,那么您可以打印单词。目前您正在为每个字母验证打印它,而不是整个过程。
  • 我同意@Pshemo - 你应该使用分而治之。也就是说,创建一个方法来检查两个字符串的字符是否匹配(根据您的条件)。这还有一个优点,即您基本上可以将显示的代码减少为仅显示该方法的代码(尽管上面的代码足够短,恕我直言)。还有一个问题:在第 3 点中,您说您想根据数组长度比较字符串。我在你的代码中没有看到?

标签: java string dictionary char


【解决方案1】:

首先,有趣的问题。我实施了我的解决方案和 Ole V.V 的解决方案。这是基于您的帖子的代码。我测试您提供的唯一测试用例,不确定这是否是您想要的。如果它没有按您的预期工作,请告诉我。

解决方案一:计算 O(nk)

public static void main(String[] args) throws IOException {
    BufferedReader reader1 = new BufferedReader(new FileReader(FILENAME));
    Scanner sc = new Scanner(System.in);

    System.out.println("Enter characters to see which english words match: ");
    String userInput = sc.next();

    Map<Character, Integer> counter = count(userInput);
    String line;
    while ((line = reader1.readLine()) != null) {
        Map<Character, Integer> lineCounter = count(line);
        if(lineCounter.equals(counter)) {
            System.out.println(line);
        }
    }
}

public static Map<Character, Integer> count(String input) {
    Map<Character, Integer> result = new HashMap<Character, Integer>();
    for (char c: input.toCharArray()) {
        result.putIfAbsent(c, 0);
        result.put(c, result.get(c) + 1);
    }

    return result;
}

方案二:排序O(nk)

public static void main(String[] args) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader(FILENAME));
    Scanner sc = new Scanner(System.in);

    System.out.println("Enter characters to see which english words match: ");
    String userInput = sc.next();
    userInput = sort(userInput);

    String line;
    while ((line = reader.readLine()) != null) {
        String sortedLine = sort(line);
        if(sortedLine.equals(userInput)) {
            System.out.println(new String(line));
        }
    }
}

// counting sort
public static String sort(String input) {
    char c[] = input.toCharArray();
    int length = c.length;
    char output[] = new char[length];

    int count[] = new int[256];
    for (int i = 0; i < length; i++) {
        count[c[i]] = count[c[i]] + 1;
    }

    for (int i = 1; i <= 255; i++) {
        count[i] += count[i - 1];
    }

    for (int i = 0; i < length; i++) {
        output[count[c[i]] - 1] = c[i];
        count[c[i]] = count[c[i]] - 1;
    }

    return new String(output);
}

【讨论】:

  • 这个的时间复杂度是O(nk),其中n是dict文件的大小,k是单词的最大长度。
  • 首先,感谢您的贡献。我已经更新了我的问题,现在我将用户直接输入的字符串的字符长度与字典中存在的字符串进行比较。我将进一步测试您的解决方案。谢谢!
【解决方案2】:

这类问题的标准解决方案是:对用户输入的字符进行排序。所以odg 会变成dgoback 会变成abck。对于字典中的每个单词,进行相同的排序。所以cab会变成abcdog会变成dgo——嘿,这和第一个用户输入是一样的,所以现在我们知道应该输出这个词了。

此解决方案的优点是您可以确保每个字母都只使用一次。它甚至会考虑重复的字母:如果相同的字母在用户输入中出现两次,它只会找到同时包含该字母两次的单词。

如果您愿意,您可以通过构建一个映射提前准备您的单词列表,其中键是按字母顺序排序的单词,值是包含这些相同字母的单词列表。所以键dgo 将映射到[dog, god] 的列表。然后,您只需对输入进行排序并进行查找。

【讨论】:

  • 您好,感谢您对此事的意见!您的建议对于包含 100k 个单词的字典仍然有效吗?谢谢
  • 是的。如果是我,我很快就会想测量检查用户输入与 100k 单词中的每一个单词所花费的时间,看看是否有必要准备一张地图。这样的准备应该会大大缩短响应时间。
【解决方案3】:

我将向您展示一个易于理解和实施但不是最快的解决方案:

可能的解决方案:数组排序

将输入字符串和字典单词视为字符数组,对其进行排序,然后进行比较:

public static boolean stringsMatchSort(String a, String b) {
    // Different length? Definitely no match!
    if (a.length() != b.length()) {
        return false;
    }

    // Turn both Strings to char arrays
    char[] charsA = a.toCharArray();
    char[] charsB = b.toCharArray();

    // Sort both arrays
    Arrays.sort(charsA);
    Arrays.sort(charsB);

    // Compare them, if equal: match!
    return Arrays.equals(charsA, charsB);
}

请注意我是如何将您的程序/问题的核心内容转化为方法的。然后,您可以轻松地在循环中使用该方法,该循环遍历字典中的所有单词。该方法不关心单词的来源:文件、集合、额外的用户输入、网络等。

它还有助于通过将程序分成更小的部分来简化您的程序,每个部分的职责更小。这通常被称为分而治之,对于新老程序员来说,在解决复杂问题时,这都是最有价值的策略之一。

其他解决方案:素数、HashMap、...

还有其他(包括更快、更优雅)的解决方案可用。看看这些相关的问题,你的问题几乎是重复的:

补充说明

根据您的应用程序,最好先将字典读入合适的集合。如果您对同一个字典执行多个“查询”,这将特别有用。或者,如果字典真的很大,您可以在创建集合的过程中删除重复项。

【讨论】:

  • 感谢您的帮助!我认为第一个解决方案更简洁,更容易理解。我将尝试实现这一点。再次感谢。
  • 迭代将接受popsoops作为匹配;这可能不是我们想要的。
  • @OleV.V.你是完全正确的,很好的观察!感谢您指出。我会尽快编辑。
  • 我最终删除了我的第二个解决方案,与第一个相比,它会变得过于复杂。相反,我将问题标记为重复,并在我的回答中引用了它 - 那里有一个非常优雅的解决方案。
猜你喜欢
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
相关资源
最近更新 更多