算法:按字典顺序排序给定索引处给定字符串的字谜

时间:2017-06-10 10:20:32

标签: java algorithm sorting optimization anagram

需要编写Algo,以按字典顺序排序的给定索引查找给定字符串的Anagram。例如:

  

考虑一个字符串: ABC ,然后所有字谜按排序顺序排列: ABC ACB   BAC BCA CAB CBA 。因此,对于索引5的值是:CAB 。另外,考虑重复的情况,例如 AADFS anagram将是指数32的DFASA

为了做到这一点,我写了Algo,但我认为应该有一些不那么复杂的东西。

import java.util.*;
public class Anagram {

static class Word {
    Character c;
    int count;

    Word(Character c, int count) {
        this.c = c;
        this.count = count;
    }
}

public static void main(String[] args) {
    System.out.println(findAnagram("aadfs", 32));
}


private static String findAnagram(String word, int index) {
    // starting with 0 that's y.
    index--;

    char[] array = word.toCharArray();
    List<Character> chars = new ArrayList<>();
    for (int i = 0; i < array.length; i++) {
        chars.add(array[i]);
    }
    // Sort List
    Collections.sort(chars);

    // To maintain duplicates
    List<Word> words = new ArrayList<>();
    Character temp = chars.get(0);
    int count = 1;
    int total = chars.size();
    for (int i = 1; i < chars.size(); i++) {
        if (temp == chars.get(i)) {
            count++;
        } else {
            words.add(new Word(temp, count));
            count = 1;
            temp = chars.get(i);
        }
    }
    words.add(new Word(temp, count));

    String anagram = "";
    while (index > 0) {
        Word selectedWord = null;
        // find best index
        int value = 0;
        for (int i = 0; i < words.size(); i++) {
            int com = combination(words, i, total);
            if (index < value + com) {
                index -= value;
                if (words.get(i).count == 1) {
                    selectedWord = words.remove(i);
                } else {
                    words.get(i).count--;
                    selectedWord = words.get(i);
                }
                break;
            }
            value += com;
        }
        anagram += selectedWord.c;
        total--;
    }
    // put remaining in series
    for (int i = 0; i < words.size(); i++) {
        for (int j = 0; j < words.get(i).count; j++) {
            anagram += words.get(i).c;
        }
    }
    return anagram;
}

private static int combination(List<Word> words, int index, int total) {
    int value = permutation(total - 1);
    for (int i = 0; i < words.size(); i++) {
        if (i == index) {
            int v = words.get(i).count - 1;
            if (v > 0) {
                value /= permutation(v);
            }
        } else {
            value /= permutation(words.get(i).count);
        }
    }
    return value;
}

private static int permutation(int i) {
    if (i == 1) {
        return 1;
    }
    return i * permutation(i - 1);
}

}

有人可以用不那么复杂的逻辑来帮助我。

3 个答案:

答案 0 :(得分:1)

我编写以下代码来解决您的问题。

我假设给定的String已排序。

排列(String prefix,char [] word,ArrayList permutations_list) 函数生成给定字符串的所有可能排列而不重复,并将它们存储在名为<的列表中强> permutations_list 即可。因此,单词: permutations_list.get(index -1)是所需的输出。

例如,假设某人给了我们“#34; aab&#34;”这个词。 我们必须递归地解决这个问题:

问题1:排列(&#34;&#34;,&#34; aab&#34;)。

这意味着我们必须解决问题:

问题2:排列(&#34; a&#34;,&#34; ab&#34;)。 字符串&#34; ab&#34;只有两个字母,因此可能的排列是&#34; ab&#34;和&#34; ba&#34;。因此,我们在permutations_list中存储单词&#34; aab&#34;和&#34; aba&#34;。

问题2已经解决。现在我们回到问题1。 我们交换第一个&#34; a&#34;第二个&#34; a&#34;我们意识到这些字母是一样的。所以我们跳过这种情况(我们避免重复)。 接下来,我们交换第一个&#34; a&#34;和&#34; b&#34;。现在,问题1已经改变,我们想要解决新的问题:

问题3:排列(&#34;&#34;,&#34; baa&#34;)。

下一步是解决以下问题:

问题4:排列(&#34; b&#34;,&#34; aa&#34;)。 字符串&#34; aa&#34;只有两个相同的字母,因此有一种可能的排列&#34; aa&#34;。因此,我们在permutations_list中存储单词&#34; baa&#34;

问题4已经解决。最后,我们回到问题3,问题3已经解决了。最终的permutations_list包含&#34; aab&#34;,&#34; aba&#34;和&#34; baa&#34;。

因此,findAnagram(&#34; aab&#34;,2)返回单词&#34; aba&#34;。

import java.util.ArrayList;
import java.util.Arrays;

public class AnagramProblem {

 public static void main(String args[]) {
     System.out.println(findAnagram("aadfs",32));
 }

 public static String findAnagram(String word, int index) {
     ArrayList<String> permutations_list = new ArrayList<String>();
     permutations("",word.toCharArray(), permutations_list);
     return permutations_list.get(index - 1);
 } 

 public static void permutations(String prefix, char[] word, ArrayList<String> permutations_list) {

    boolean duplicate = false;

    if (word.length==2 && word[0]!=word[1]) {
        String permutation1 = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
        permutations_list.add(permutation1);
        String permutation2 = prefix + String.valueOf(word[1]) + String.valueOf(word[0]);
        permutations_list.add(permutation2);
        return;
    }
    else if (word.length==2 && word[0]==word[1]) {
        String permutation = prefix + String.valueOf(word[0]) + String.valueOf(word[1]);
        permutations_list.add(permutation);
        return;
    }

    for (int i=0; i < word.length; i++) {
        if (!duplicate) {
            permutations(prefix + word[0], new String(word).substring(1,word.length).toCharArray(), permutations_list);
        }
        if (i < word.length - 1) {
            char temp = word[0];
            word[0] = word[i+1];
            word[i+1] = temp;
        }
        if (i < word.length - 1 && word[0]==word[i+1]) duplicate = true;
        else duplicate = false;
    }


 }




}

答案 1 :(得分:0)

如果你考虑按字母顺序生成字谜,我认为你的问题会变得简单得多,所以你不必在事后对它们进行排序。

以下代码(来自Generating all permutations of a given string)生成String的所有排列。这些排列的顺序由输入String的初始顺序给出。如果事先对String进行排序,那么将按排序顺序添加字谜。

为防止重复,您只需维护一组已添加的字符串即可。如果此Set不包含您要添加的anagram,则可以安全地将其添加到字谜列表中。

以下是我所描述的解决方案的代码。我希望你发现它比你的解决方案更简单。

public class Anagrams {

private List<String> sortedAnagrams;
private Set<String> handledStrings;

public static void main(String args[]) {
    Anagrams anagrams = new Anagrams();
    List<String> list = anagrams.permutations(sort("AASDF"));
    System.out.println(list.get(31));
}

public List<String> permutations(String str) {
    handledStrings = new HashSet<String>();
    sortedAnagrams = new ArrayList<String>();
    permutation("", str);
    return sortedAnagrams;
}

private void permutation(String prefix, String str) {
    int n = str.length();
    if (n == 0){
        if(! handledStrings.contains(prefix)){
            //System.out.println(prefix);
            sortedAnagrams.add(prefix);
            handledStrings.add(prefix);
        }
    }
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n));
    }
}

public static String sort(String str) {
    char[] arr = str.toCharArray();
    Arrays.sort(arr);
    return new String(arr);
}

}

答案 2 :(得分:0)

如果你创建一个&#34;下一个排列&#34;将数组更改为下一个词典排列的方法,然后你的基本逻辑可能只是在循环中调用该方法n-1次。

对于可以找到here的代码,有一个很好的描述。这里有基本的伪代码和从该页面改编的Java示例。

/*
1. Find largest index i such that array[i − 1] < array[i].
   (If no such i exists, then this is already the last permutation.)
2. Find largest index j such that j ≥ i and array[j] > array[i − 1].
3. Swap array[j] and array[i − 1].
4. Reverse the suffix starting at array[i].
*/

boolean nextPermutation(char[] array) {
    int i = array.length - 1;
    while (i > 0 && array[i - 1] >= array[i]) i--;
    if (i <= 0) return false;
    int j = array.length - 1;
    while (array[j] <= array[i - 1]) j--;
    char temp = array[i - 1];
    array[i - 1] = array[j];
    array[j] = temp;
    j = array.length - 1;
    while (i < j) {
        temp = array[i];
        array[i] = array[j];
        array[j] = temp;
        i++;
        j--;
    }
    return true;
}