加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java字符串排列和组合查找

发布时间:2020-12-14 16:38:22 所属栏目:Java 来源:网络整理
导读:我正在编写一个 Android word应用程序.我的代码包括一个方法,可以找到最小长度为3的7个字符串的字符串和子字符串的所有组合.然后将所有可用组合与字典中的每个单词进行比较,以查找所有有效的单词.我正在使用递归方法.这是代码. // Gets all the permutations
我正在编写一个 Android word应用程序.我的代码包括一个方法,可以找到最小长度为3的7个字符串的字符串和子字符串的所有组合.然后将所有可用组合与字典中的每个单词进行比较,以查找所有有效的单词.我正在使用递归方法.这是代码.
// Gets all the permutations of a string.
void permuteString(String beginningString,String endingString) {
    if (endingString.length() <= 1){
        if((Arrays.binarySearch(mDictionary,beginningString.toLowerCase() +   endingString.toLowerCase())) >= 0){
            mWordSet.add(beginningString + endingString);
        }
    }
    else
        for (int i = 0; i < endingString.length(); i++) {
            String newString = endingString.substring(0,i) + endingString.substring(i + 1);
            permuteString(beginningString + endingString.charAt(i),newString);
      }
}
// Get the combinations of the sub-strings. Minimum 3 letter combinations
void subStrings(String s){
    String newString = "";
    if(s.length() > 3){
        for(int x = 0; x < s.length(); x++){
            newString = removeCharAt(x,s);
            permuteString("",newString);
            subStrings(newString);
        }
    }
}

上面的代码运行正常,但是当我将其安装在我的Nexus上时,我意识到它运行有点太慢了.完成需要几秒钟.大概3或4秒是不能接受的.
现在我已经在手机上玩过一些文字游戏,他们会立即计算一个字符串的所有组合,这使我相信我的算法效率不高,可以改进.谁能帮忙?

public class TrieNode {
TrieNode a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;
TrieNode[] children = {a,z};
private ArrayList<String> words = new ArrayList<String>();

public void addWord(String word){
    words.add(word);
}
public ArrayList<String> getWords(){
    return words;
}
}
public class Trie {

static String myWord;
static String myLetters = "afinnrty";
static char[] myChars;
static Sort sort;
static TrieNode myNode = new TrieNode();
static TrieNode currentNode;
static int y = 0;
static ArrayList<String> availableWords = new ArrayList<String>();

public static void main(String[] args) {

    readWords();
    getPermutations();
}
public static void getPermutations(){
    currentNode = myNode;
    for(int x = 0; x < myLetters.length(); x++){
        if(currentNode.children[myLetters.charAt(x) - 'a'] != null){
            //availableWords.addAll(currentNode.getWords());
            currentNode = currentNode.children[myLetters.charAt(x) - 'a'];
            System.out.println(currentNode.getWords() + "" + myLetters.charAt(x));
        }
    }
    //System.out.println(availableWords);
}
public static void readWords(){
    try {
        BufferedReader in = new BufferedReader(new FileReader("c://scrabbledictionary.txt"));
        String str;
        while ((str = in.readLine()) != null) {
            myWord = str;
            myChars = str.toCharArray();
            sort = new Sort(myChars);
            insert(myNode,myChars,0);
        }
        in.close();
    } catch (IOException e) {
    }
}
public static void insert(TrieNode node,char[] myChars,int x){    
    if(x >= myChars.length){
        node.addWord(myWord);
        //System.out.println(node.getWords()+""+y);
        y++;
        return;
    }
    if(node.children[myChars[x]-'a'] == null){
        insert(node.children[myChars[x]-'a'] = new TrieNode(),x=x+1);
    }else{
        insert(node.children[myChars[x]-'a'],x=x+1);
    }
}
}

解决方法

在您目前的方法中,您正在查找每个子字符串的每个排列.所以对于“abc”,你需要查找“abc”,“acb”,“bac”,“bca”,“cab”和“cba”.如果您想查找“排列”的所有排列,您的查找次数将近500,000,这是在您甚至查看其子串之前.但是,通过预处理字典,我们可以将其减少到一个查找,而不管长度.

这个想法是将字典中的每个单词都放入一些数据结构,其中每个元素包含一组字符,以及包含(仅)这些字符的所有单词的列表.因此,例如,您可以构建一个二叉树,它将包含一个包含(排序)字符集“abd”和单词列表[“bad”,“dab”]的节点.现在,如果我们要查找“dba”的所有排列,我们将其排序为“abd”,并将其查找到树中以检索列表.

正如鲍曼指出的那样,tries非常适合存储这种数据. trie的优点是查找时间仅取决于您的搜索字符串的长度 – 它与您的字典的大小无关.由于您将存储相当多的单词,并且大多数搜索字符串将很小(大部分将是您的递归最低级别的3个字符的子串),这种结构是理想的.

在这种情况下,您的特技的路径将反映字符集而不是单词本身.所以,如果你的整个字典都是[“坏”,“dab”,“cab”,“cable”],你的查找结构将会如下所示:

有一个时间/空间的折中方式实现这一点.在最简单(最快)的方法中,每个节点只包含单词列表,以及一个子节点[26].这可以让你定期找到你所在的孩子,只要看看孩子[s.charAt(i) – ‘a’](其中s是你的搜索字符串,我是你当前的这个特技的深度).

缺点是,你的大部分孩子阵列大部分都是空的.如果空间是一个问题,您可以使用更紧凑的表示,如链表,动态数组,哈希表等.但是,这些代价是潜在地需要在每个节点进行多个内存访问和比较,而不是简单的数组访问上面.但是,如果浪费的空间超过您的整个字典超过几兆字节,我会感到惊讶,因此基于阵列的方法可能是您最好的选择.

使用trie,您的整个置换功能将被替换为一个查找,从O(N!log D)(其中D是字典的大小,您的字符串的大小,N)到O(N log N)(因为你需要排序字符;查找本身是O(N)).

编辑:我已经把这个结构的一个(未经测试的)实现:http://pastebin.com/Qfu93E80

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读