簡體   English   中英

是否有一種有效的算法可以輸出存儲在按字典順序排列的排序列表中的所有字符串,這些字符串是輸入字符串的排列?

[英]Is there an efficient algorithm for outputting all strings stored in a sorted lexicographically list that are a permutation of an input string?

我想為這個問題找到最有效的算法:給定一個字符串str和一個僅由小寫英文字符組成並按字典順序排列的字符串列表lst ,找到lst中所有作為str排列的單詞。

例如: str = "cat", lst = {"aca", "acc", "act", "cta", "tac"}

會返回:{"act", "cta", "tac"}

我已經有一個算法沒有利用lst按字典順序排列這一事實,我正在尋找利用這一事實的最有效算法。

我的算法是這樣的:

public List<String> getPermutations(String str, List<String> lst){
  List<String> res = new ArrayList<>();
  for (String word : lst)
        if (checkPermutation(word, str))
            res.add(word);
  return res;
}


public boolean checkPermutation(String word1, String word2) {
    if (word1.length() != word2.length())
        return false;
    int[] count = new int[26];
    int i;
    for (i = 0; i < word1.length(); i++) {
        count[word1.charAt(i) - 'a']++;
        count[word2.charAt(i) - 'a']--;
    }
    for (i = 0; i < 26; i++)
        if (count[i] != 0) {
            return false;
        }
    return true;
}

總運行時間為 O(NK),其中 N 是lst中的字符串數,k 是str的長度。

一個簡單的優化(只對非常大的數據集有意義,因為它並沒有真正改善 O(NK):

  • 將傳入str的所有字符放入 Set strChars
  • 現在:迭代列表中的單詞時:獲取每個條目的第一個字符
  • if strChars.contains(charFromListEntry ): 檢查它是否是一個排列
  • else:顯然,那個列表詞不能是一個排列

注意:排序順序在這里沒有多大幫助:因為您仍然需要檢查列表中下一個字符串的第一個字符。

可能還有其他檢查來避免昂貴的checkPermutation()運行,例如首先比較單詞的長度:當列表字符串比輸入字符串短時,它顯然不可能是所有字符的排列。

但如前所述,最后您必須遍歷列表中的所有條目並確定一個條目是否是排列。 沒有辦法避免相應的“循環”。 您唯一可以影響的是循環中發生成本。

最后:如果您的字符串列表是一個集合,那么您可以“簡單地”計算傳入str的所有排列,並檢查每個排列是否包含在該集合中。 但是當然,為了將一個列表變成一個集合,你必須迭代那個東西。

您可以遍歷字符串的所有排列並使用二進制搜索檢查列表中的每個元素,而不是遍歷列表並檢查每個元素是否是字符串的排列。

例如

public List<String> getPermutations(String str, List<String> lst){
    List<String> res = new ArrayList<>();
    perm(str, (1L << str.length()) - 1, new StringBuilder(), lst, res);
    return res;
}

private void perm(String source, long unused,
                  StringBuilder sb, List<String> lst, List<String> result) {
    if(unused == 0) {
        int i = Collections.binarySearch(lst, sb.toString());
        if(i >= 0) result.add(lst.get(i));
    }
    for(long r = unused, l; (l = Long.highestOneBit(r)) != 0; r-=l) {
        sb.append(source.charAt(Long.numberOfTrailingZeros(l)));
        perm(source, unused & ~l, sb, lst, result);
        sb.setLength(sb.length() - 1);
    }
}

現在,時間復雜度為 O(K. × log N),不一定比您的方法的 O(NK) 好。 它在很大程度上取決於 K 和 N 的大小,如果字符串真的很短而列表真的很大。 它可能有一個優勢。

有很多可以想象的優化。 例如,代替構建每個排列,然后進行二進制搜索,每個遞歸步驟可以進行部分搜索以確定下一步的潛在搜索范圍,並在很明顯不能包含排列時跳過。 雖然這可以顯着提高性能,但它不能改變基本的時間復雜度,即最壞的情況。

暫無
暫無

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

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