【问题标题】:How can I reduce the time of the search? (edit1)如何减少搜索时间? (编辑1)
【发布时间】:2021-06-09 11:57:40
【问题描述】:

我的代码有问题,调用方法somme_2时运行程序耗时太长,我想减少运行时间。顺便说一句,我在这个程序中使用的 txt 文件包含近 500_000 行。你知道如何解决它吗?

这是我的主线

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) throws IOException {
        Somme2 somme2 = new Somme2("src/dico.txt");
        //somme2.remove(alphabeticalOrder("Amsterdam" + "ADN"), "adn");
        //somme2.remove(alphabeticalOrder("Amsterdam" + "ADN"), "riflassent");
        somme2.somme_2(alphabeticalOrder("volontiers" + "tranquillement"));

    }

    private static String alphabeticalOrder(String word) {
        word = word.toLowerCase();
        List<Character> list = new ArrayList<>();
        for (int i = 0; i < word.length(); i++) {
            list.add(word.charAt(i));
        }
        Collections.sort(list);
        String string = "";
        for (int i = 0; i < list.size(); i++) {
            string = string + list.get(i);
        }
        return string;
    }
}

这是我的类,其中包含 somme_2 函数:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

public class Somme2 {
    private String path;

    public Somme2(String path) {
        this.path = path;
    }

    /***
     * values() returns a list which contains every word in our file.
     * @return List<String>
     * @throws FileNotFoundException
     */
    private List<String> values() throws IOException {
        return Files.readAllLines(Path.of(path));
    }

    /***
     * alphabeticalOrder() returns the word in the parameter, alphabetically
     * @param word
     * @return String
     */
    private String alphabeticalOrder(String word) {
        word = word.toLowerCase();
        char[] chars = word.toCharArray();
        Arrays.sort(chars);
        return new String(chars);
    }

    /***
     * addToHashMap() returns a hashMap, which uses as a key alphabetically words, and as value classical words
     * @return HashMap<String, List<String>>
     * @throws FileNotFoundException
     */
    private HashMap<String, List<String>> addToHashMap() throws IOException {
        HashMap<String, List<String>> hashMap = new HashMap<>();
        for (String value : values()) {
            String word = alphabeticalOrder(value);
            if (hashMap.containsKey(word)) {
                hashMap.get(word).add(value);
            }
            else {
                List<String> list = new ArrayList<>();
                list.add(value);
                hashMap.put(word, list);
            }
        }
        return hashMap;
    }

    /***
     * findTheLetter return the index of the letter
     * @param letter
     * @param word
     * @return
     */
    private int findTheLetter(char letter, char[] word) {
        for (int i = 0; i < word.length; i++) {
            if (word[i] == letter) {
                return i;
            }
        }
        return 0;
    }

    private char[] removeLetter(char letter, char[] word) {
        int x = findTheLetter(letter, word);
        char[] newWord;
        if (word.length == 1) {
            newWord = new char[word.length];
        } else {
            newWord = new char[word.length - 1];
        }
        for (int i = 0; i < word.length - 1; i++) {
            if (i < x) {
                newWord[i] = word[i];
            }
            else {
                newWord[i] = word[i + 1];
            }
        }
        return newWord;
    }

    public String remove(String word, String string) {
        char[] myWord = string.toCharArray();
        char[] words = word.toCharArray();
        for (int i = 0; i < string.length(); i++) {
            words = removeLetter(myWord[i], words);
        }
        return new String(words);
    }


    /***
     * somme_2
     * @param alph
     * @throws FileNotFoundException
     */
    public void somme_2(String alph) throws IOException {
        HashMap<String, List<String >> hashMap = addToHashMap();
        List<String> strings = new ArrayList<>();
        strings.addAll(hashMap.keySet());
        String alphWord = "" + alph;
        for (String string : strings) {
            if (hashMap.containsKey(remove(alphabeticalOrder(alphWord), string))) {
                System.out.println("\"" + hashMap.get(string) + "\" and \"" + hashMap.get(remove(alphWord, string)) + "\" give \"" + alphWord + "\"");
                return;
            }
        }
        System.out.println("There are no words");
    }
}

如果你想知道,这是 txt 文件的一部分:

A
ABS
ADN
ADNc
ADP
ADSL
AIEA
ARN
ARNm
ASBL
ASC
ASCII
AUD
Aarhus
Aaron
Aarschot
Abbeville
Abd
Abdelkader
Abel
Abidjan
Abitibi-Témiscamingue
Abkhazie
Abraham
Abu
Abuja
Abymes
Abyssinie
Acadie
Acapulco
Accra
Achaïe
Achgabat

我只是解决了时间问题,但现在我的程序有时会显示如下结果: “[宪法化]”和“[V,v]”给出“aeeeiilllmnnnooqrrstttuv”

这是错误的,因为按字母顺序排列的“宪法”+“V”不给出“aeeeiilllmnnnooqrrstttuv”。

感谢您的帮助!

【问题讨论】:

  • somme_2的目的是什么?
  • 顺便说一句:x.hashCode() == y.hashCode() 并不意味着 x == yx.equals(y);它仅表示x maybe == ymaybe x.equals(y)
  • 你用的是什么java版本?
  • somme_2 的目的是在我的文件中找到 2 个按字母顺序排列的单词,与参数中我的单词相等,并打印 ""word1" 和 "word2" 给出 "parameter""跨度>
  • 关于版本,我使用java 15 JDK

标签: java performance hashmap


【解决方案1】:

好的,我只是添加一个 if 来检查我的测试是否正确,感谢您的帮助!

    /***
     * somme_2
     * @param alph
     * @throws FileNotFoundException
     */
    public void somme_2(String alph) throws IOException {
        HashMap<String, List<String >> hashMap = addToHashMap();
        List<String> strings = new ArrayList<>();
        strings.addAll(hashMap.keySet());
        String alphWord = "" + alph;
        for (String string : strings) {
            if (hashMap.containsKey(remove(alphabeticalOrder(alphWord), string))) {
                if (alphabeticalOrder(string + remove(alphabeticalOrder(alphWord), string)).equals(alphabeticalOrder(alphWord))) {
                    System.out.println("\"" + hashMap.get(string) + "\" and \"" + hashMap.get(remove(alphWord, string)) + "\" give \"" + alphWord + "\"");
                    System.out.println("\"" + string + "\" and \"" + remove(alphWord, string) + "\" give \"" + alphWord + "\"");
                    return;
                }
            }
        }
        System.out.println("There are no words");
    }

【讨论】:

    【解决方案2】:

    你可以肯定地做一件事。让我列出你可以做些什么来改善你的运行时间:

    1. 将 word.length() 移到 for 循环之外,例如:String wordSize=word.length();
    2. 将 strings.size() - 1 移到 for 循环之外,如 int stringsSize=strings.size()-1;
    3. 如果是 Java,您可以选择 TreeSet,它是 Set 接口的实现。您可以将 Collection 对象传递给此类的构造函数,该构造函数将自动对对象进行排序。此外,当您添加任何对象时,它将按排序顺序放置。
    4. 也不要 system.out.println,因为它是同步方法,最好将输出记录到文件位置..

    希望这个答案可以帮助您改善运行时间。

    【讨论】:

    • 你好,我做了你的2个建议,我不能做第三个,因为我必须使用HashMap,而且程序运行时间仍然太长,至少2或3分钟跨度>
    【解决方案3】:

    有很多方法可以改进您的代码。

    让我们从最重要的部分开始:算法

    您遍历所有可能的配对并检查条件,但您只能遍历所有单词 1 次,并且为每个单词尝试找到“互补”单词。

    示例:alph = 'aabbcc' 并且在当前对所有单词的迭代中,我们拥有word = 'acc'。我们想在我们的文件中找到另一个词 (complementaryWord),它与 ​​word 结合将得到 alph。显然,这个complementaryWord 应该是abb (abb + acc = aabbcc),而且这个词很容易找到,因为你已经有了 hashmap。

    总体而言,它将复杂性从O(n^2) 提高到O(n)

    代码改进

    • alphabeticalOrder 做了很多不必要的对象分配,整体看起来不太好。尝试使用char[] 直接在这里工作。此外,如果您知道单词只能包含特定的字母集(例如仅包含拉丁字母或其他一些字母),您可以使用 bucket sort 来提高时间复杂度。

    • Scanner 对于大输入文件来说很慢。例如,使用BufferedRead 或使用更新的Files.readAllLines() 读取行。

    • 删除重复的计算:例如,计算一次alphabeticalOrder(value)并将结果存储在变量中。

    • addToHashMap()use computeIfAbsent()to make it shorter and clearer

    • 使用equals() 来比较字符串而不是hashCode()。如 cmets 所述,如果 s1.hashCode() == s2.hashCode() 并不意味着 s1.equals(s2)

    【讨论】:

    • 除了computeIfAbsent(),我什么都做了,因为我试过了,但我不明白你怎么用它。但这仍然太长了,比如“至少 3 分钟”
    • @alonso00235 请在原始问题中添加您的新代码
    • @alonso00235 您没有实现该算法,这将使您减少 90% 的时间。另外,请发布没有多余 cmets 的代码,并且仅使用与问题相关的方法(即从您的代码中删除所有未使用的方法),我们会更容易阅读它
    • 我只是更新我的帖子,如果你想看 =)
    猜你喜欢
    • 1970-01-01
    • 2017-02-15
    • 2021-11-28
    • 1970-01-01
    • 2012-05-19
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    相关资源
    最近更新 更多