簡體   English   中英

Java中高效的單詞創建算法

[英]Efficient algorithm for word creation in java

我正在使用libGDX框架開發文字游戲,並且想要實現基本的提示功能,系統可以從板上提供的17個字母中生成一個有效的7個字母的單詞。 現在,板上的17個字母(從中選擇)的設置是完全隨機的,因此我不能使用預定的提示單詞作為提示(例如4個圖片中的1個單詞)。

我的解決方案是通過從提供的17個字母中找到每種可能的7個字母組合來進行一些組合。 接下來,我對每個組合進行排列,並使用wordSet English Lexicon對其進行交叉檢查,然后我得到的第一個有效單詞將是提示單詞。

正如您已經猜到的那樣,知道17個置換7已經等於9,800萬個可能的置換,此過程非常艱巨。 為了解決這個問題,我使用了FixedThreadPool將置換任務(分成大約20個工作線程)進行拆分,並且現在我的單詞搜索相對較快,但是缺點是,這會導致低端設備嚴重滯后。

任何有關如何做出更好的提示詞搜索算法或改進我上面解釋的方法的建議將不勝感激。

使用單詞列表構建特里/前綴樹:

在此處輸入圖片說明

您可以從17個可用字母中選擇一個隨機字母,然后僅使用17個字母中的字母開始遍歷。第一個帶有標記表明該單詞結束的標記的節點可能是建議。

許多預測性文本程序都使用這種結構來猜測您正在鍵入的單詞,或者如果您在圖形中離標記單詞結尾的節點不太遠,則可以幫助您輸入錯誤。 在空間上更好,因為樹的深度由最長的單詞決定。 但是,您不會在以下情況下浪費空間:

do
dog
doggy
done
dunce

您只存儲:

                d
               / \
             *o   u
             / \   \
           *g   n   n
           /     \   \
          g      *e   c
         /             \
       *y              *e

其中*是一個布爾型標志,指示單詞的結尾。

時間復雜度:

通過O(n)查找文本字符串是否是單詞,其中n是單詞的長度。

該網站似乎進行了一些優化: https : //www.geeksforgeeks.org/trie-insert-and-search/

空間取決於您是否使用數組,指針或哈希圖實現。

有幾種優化方法:

  • 無需生成數百萬個組合並對其進行測試,而是遍歷英語單詞列表並針對您的17個字母進行測試。 不用進行數百萬的測試,您就可以進行數以千計的測試。
  • 測試是否可以使用字母計數由您的17個字母組成一個單詞,而不是實際按特定順序生成字母字符串並與單詞進行比較。 這意味着您不必生成每個可能的字母順序。

要實現第二個優化,必須以一種可以輕松比較字母數的方式將單詞存儲在單詞列表中。 一種簡單的方法是將每個單詞與另一個字符串(由按字母順序排序的所有字母組成)存儲在一起。 例如,您將“奶酪”和“ ceeehs”存儲為一對。 您可以計算字母的行數,看看每個字母是否足夠。

在過程開始時,您可以計算出17個字母中有多少個字母並將它們存儲在數組中。 然后瀏覽您的單詞列表並測試每個單詞,如下所示:

int[] letter_counts = new int[26]; // how many of each letter of the
                                   // alphabet you have in your 17 letters

boolean test_word(String word)  // pass in the sorted string e.g "ceeehs"
{
    char prev = '\0'; // use this for detecting repeating letters
    int count = 0;
    for(int i = 0; i < word.length(); i++)
    {
        char c = word.charAt(i);
        if(c != prev)
        {
            prev = c;
            count = 0;
        }
        count++;
        if(letter_counts[(int)c - 'a'] < count)
            return false; // not enough letters
    }
    return true;
}

為避免偏愛單詞列表中較早的單詞(因為一旦找到單詞就停止了),您可以從單詞列表中的任意位置開始,然后重新開始。

這種方法絕不是最佳方法,但可能足夠快且易於實現。

我現在無法真正測試任何有關速度的內容,但是如果您對詞典進行排序,則可以在其上使用搜索算法:首先找到所有位置,這些位置的單詞列表以17個可用字母之一開頭。 然后,您將在每個列表中查找以其他16個字母之一開頭的列表,並繼續進行此操作,直到出現任何長度允許的單詞。

作為一個簡單的示例,請考慮以下內容:

String[] lexicon = {"parrot", "postal", "office", "spam"};
char[] letters = {'p', 'o', 's', 't', 'a', 'l'};

這將產生中間可能性:

{"parrot", "postal", "office", "spam"}  (1 letter  matched)
{"parrot", "postal", "spam"}            (2 letters matched)
{"postal", "spam"}                      (3 letters matched)
{"parrot"}                              (4 letters matched)

此時,您可以繼續搜索算法,或者注意只剩下一個選項,然后使用其他測試來查看是否允許。

該算法將要求您最多使用C(17, 7) = 19,448搜索。 您也可能會提高對每個單個字母使用完整二進制搜索的成本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM