当前位置: 首页 > 知识库问答 >
问题:

内存不足

公孙辰龙
2023-03-14

我正在努力解决古老的字谜问题。多亏了许多教程,我能够迭代一组字符串,递归地找到所有的排列,然后将它们与英语单词列表进行比较。我发现的问题是,在大约三个单词之后(通常是关于“变形”之类的东西),我会得到一个OutOfMemory错误。我试着把我的批分成小的集合,因为它似乎是消耗我所有内存的递归部分。但即使只是“变形”也把它锁起来了...

Scanner scanner = new Scanner(resource.getInputStream());
   while (scanner.hasNext()) {
       String s = scanner.nextLine();
        uniqueWords.add(s.toLowerCase());
   }
List<List<String>> subSets = Lists.partition(new ArrayList(uniqueWords), SET_SIZE);

for (List<String> set: subSets) {
      // tried created as class attribute & injection, no difference 
      AnagramGenerator anagramGenerator = new AnagramGenerator();
      List<Word> anagrams = anagramGenerator.createWordList(set);
      wordsRepository.save(anagrams);
      LOGGER.info("Inserted {} records into the database", anagrams.size());
 }
public class AnagramGenerator {

private Map<String, List<String>> map = new Hashtable<>();
public List<Word> createWordList(List<String> dictionary) {

   buildAnagrams(dictionary);

   List<Word> words = new ArrayList<>();
   for (Map.Entry<String, List<String>> entry : map.entrySet()) {
       words.add(new Word(entry.getKey(), entry.getValue()));
   }
    return words;
   }

private Map<String, List<String>> buildAnagrams(List<String> dictionary) {

        for (String str : dictionary) {
            String key = sortString(str);
            if (map.get(key) != null) {
                map.get(key).add(str.toLowerCase());
            } else {
                if (str.length() < 2) {
                    map.put(key, new ArrayList<>());
                } else {
                    Set<String> permutations = permutations(str);
                    Set<String> anagramList = new HashSet<>();

                    for (String temp : permutations) {
                        if (dictionary.contains(temp) && !temp.equalsIgnoreCase(str)) {
                            anagramList.add(temp);
                        }
                    }
                    map.put(key, new ArrayList<>(anagramList));
                }
            }
        }
        return map;
    }

   private Set<String> permutations(String str) {    
        if (str.isEmpty()) {
            return Collections.singleton(str);
        } else {
            Set<String> set = new HashSet<>();
            for (int i = 0; i < str.length(); i++)
                for (String s : permutations(str.substring(0, i) + str.substring(i + 1)))
                    set.add(str.charAt(i) + s);
            return set;
        }
    }

编辑:根据出色的反馈,我已经将生成器从排列更改为工作查找:

public class AnagramGenerator {
private Map<String, Set<String>> groupedByAnagram = new HashMap<String, Set<String>>();

    private Set<String> dictionary;

    public AnagramGenerator(Set<String> dictionary) {

        this.dictionary = dictionary;
    }

 public List<Word> searchAlphabetically() {

        List<Word> words = new ArrayList<>();
        for (String word : dictionary) {
            String key = sortString(word);
            if (!groupedByAnagram.containsKey(key)) {
                groupedByAnagram.put(key, new HashSet<>());
            }
            if (!word.equalsIgnoreCase(key)) {
                groupedByAnagram.get(key).add(word);
            }
        }

        for (Map.Entry<String, Set<String>> entry : groupedByAnagram.entrySet()) {
            words.add(new Word(entry.getKey(), new ArrayList(entry.getValue())));
        }

        return words;
    }
 private String sortString(String goodString) {

        char[] letters = goodString.toLowerCase().toCharArray();
        Arrays.sort(letters);
        return new String(letters);
    }

它有一点更多的调整,所以我不添加一个词,因为它是自己的字形,但除此之外,这似乎是炽热的快速。而且,代码要干净得多。谢谢大家!

共有1个答案

柏夕
2023-03-14

正如较长的单词所指出的那样,排列的数量很快就变得巨大。

Debian上的/usr/share/dict/British-English有99,156行。有更长的单词列表,但让我们用它作为一个例子。

一个九个字母的单词的排列数是9!=362,880

10! milliseconds = ~1 hour
12! milliseconds = ~5.54 days
15! milliseconds = ~41.44 years
 sorted_input = sort_alphabetically(input_word)
 for each dictionary_word // probably a file readline()
     sorted_dictionary_word = sort_alphabetically(dictionary_word)
     if(sorted_dictionary_word = sorted_input)
         it's an anagram! Handle it
     end 
 end
  multimap = new MultiMap<String, String> // or whatever

  def build_dict:
      for each dictionary_word // probably a file readline()
          multimap.add(
               sort_alphabetically(dictionary_word), 
               dictionary_word)
      end
  end

  def lookup_anagrams(word):
      return multimap.get(sort_alphabetically(word))
  end 

这占用了适度的内存(整个字典,加上一点键和映射开销),但意味着一旦创建了结构,您就可以一遍又一遍地查询,成本确实非常低。

如果你想找到两个字的字谜,你将需要一个更复杂和有趣的算法。但即便如此,避免暴力强迫整个排列搜索空间对你的成功至关重要。

 类似资料:
  • 问题内容: 我今天遇到一个奇怪的问题。对于其他人来说,这可能是一个简单的答案,但这让我感到困惑。为什么下面的代码会导致内存错误? 我得到了这两个错误之一…第一个是在节点的解释器中运行此代码时,第二个是通过nodeunit运行它时: 严重错误:CALL_AND_RETRY_2分配失败-内存不足 严重错误:JS分配失败-内存不足 问题答案: 当我尝试访问阵列时会发生这种情况。但是获取长度却没有。

  • 问题内容: 今天,我运行了用于文件系统索引编制的脚本,以刷新RAID文件索引,并在4小时后崩溃并出现以下错误: 服务器配备16GB RAM和24GB SSD交换。我非常怀疑我的脚本是否超过了36gb的内存。至少不应该 脚本使用文件元数据(修改日期,权限等,无大数据)创建存储为对象数组的文件索引 过去,我曾经用此脚本经历过奇怪的节点问题,这使我不得不这样做。在处理诸如String之类的大文件时,由于

  • 我正在PyTorch中运行一个评估脚本。我有许多经过训练的模型(*.pt文件),我将其加载并移动到GPU,总共占用270MB的GPU内存。我使用的批量大小为1。对于每个示例,我加载一个图像并将其移动到GPU。然后,根据样本,我需要运行一系列经过训练的模型。有些模型以张量作为输入和输出。其他模型的输入是张量,输出是字符串。序列中的最终模型总是有一个字符串作为输出。中间张量临时存储在字典中。当模型使用

  • STS不断崩溃,项目文件夹中的日志如下: 它始于我使用Winmerge比较和修改STS之外的java、pom和属性文件时

  • 我是刚到爪哇的。我只是试图了解如何处理堆内存溢出及其原因。有人能在下面的代码中帮助我为什么它会抛出这个错误吗。我怎么能避免。 错误: 线程“main”Java.lang.OutOfMemoryError中出现异常:Java.util.arrays.copyof(arrays.Java:2361)在Java.lang.AbstractStringBuilder.ExpandCapacity(Abst

  • 我将代码库从1.1.1升级为使用storm 2.0.0。现在我观察到,如果我在本地模式下运行拓扑,几分钟后它就会耗尽内存。 [THREAD ID=AsyncLocalizer执行器-2-EventThread]Dev-APC180-本地o. a. s. s. o. a. z.ClientCnxn错误,同时调用监视器java.lang.OutOfMemoryError:无法创建新的本机线程在java