根据字母顺序查找字符串的 "permutation"

Finding strings' "permutation" based on alphabetical order

我想请教一下,是否有更有效的方法来根据字母顺序查找字符串的排列,就像我下面的代码一样。 我正在处理长达 16 个字符的字符串和大量数据,并且 运行 我的程序占用了太多时间和内存。

问题的基本表示

输入:字母表

输出:16752348

所以单词"alphabet"中的字母'a'是字母表中的第一个,将其标记为索引1,然后在第五个位置出现另一个'a',将其标记为2,然后'b' 排在第六位,标记为 3 以此类推..

在代码中我没有使用数字作为索引,而是使用字符,所以从 ASCII 值的值 65 开始。 (因为我使用测试长字符串。但它不会改变主要目的)。所以我的程序的输出将是

输入:字母表

输出:AFGEBCDH

public static String perm(String word){

    char[] perm = new char[word.length()];
    char[] wordArray = word.toCharArray();
    char[] sortedWord = new char[word.length()];

    sortedWord = word.toCharArray();
    Arrays.sort(sortedWord);

    for (int i=0; i<word.length(); i++){
        for (int j=0; j<word.length(); j++){

            if (sortedWord[i] == wordArray[j]){
                perm[j] = (char)(65+i);  //from A
                wordArray[j] = '.';

                j = word.length();    //in case, if the word has more of the tested char, we jump to the end of the cycle
            }
        }
    }

    return String.valueOf(perm);
}

public static void main (String [] args){
    System.out.println(perm("alphabet"));
}

WRT内存占用,你贴的程序用不了多少。你在真正的代码中对返回的字符串做了什么?

就性能而言,这应该会好一点:

import java.util.Arrays;

class El implements Comparable<El>{
 char c;
 int idx;

 public El(char c, int idx) {
  this.c = c;
  this.idx = idx;
 }

 public int compareTo(El other) {
   return Character.compare(c, other.c);
 }
}

public class Perm {
  public static String perm(String word){
    int l = word.length();
    El[] els = new El[l];
    for (int i=0; i<l; i++) {
      els[i] = new El(word.charAt(i), i);
    }
    Arrays.sort(els);
    StringBuilder sb = new StringBuilder(l);
    for (int i=0; i<els.length; i++) {
      sb.append((char)('A' + els[i].idx));
    }
    return sb.toString();
  }

  public static void main (String [] args){
    System.out.println(perm("alphabet"));
  }
}

试试这个:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class alphabet {
    public static List<CharIndexHolder> charlist = new ArrayList<CharIndexHolder>();

    public static String perm(String word) {
        char[] perm = new char[word.length()];
        char[] wordArray = word.toCharArray();
        char[] sortedWord = new char[word.length()];

        sortedWord = word.toCharArray();
        Arrays.sort(sortedWord);

        for (int i=0; i<word.length(); i++){
            for (int j=0; j<word.length(); j++){

                if (sortedWord[i] == wordArray[j]){
                    perm[j] = (char)(65+i);  //from A
                    wordArray[j] = '.';

                    j = word.length();    //in case, if the word has more of the tested char, we jump to the end of the cycle
                }
            }
        }   
        return String.valueOf(perm);
    }

    public static String perm2(String word) {
        charlist.clear();
        for(int i = 0; i < word.length(); i++) {
            charlist.add(new CharIndexHolder(word.charAt(i), i));
        }
        Collections.sort(charlist);
        for(int i = 0; i < charlist.size(); i++) {
            charlist.get(i).assignedindex = i;
        }
        char[] result = new char[word.length()];
        for(int i = 0; i < result.length; i++) {
            CharIndexHolder cur = charlist.get(i);
            result[cur.index] =(char) (charlist.get(i).assignedindex + 65);
        }
        return new String(result);
    }

    public static void main (String [] args){
        System.out.println(perm("alphabet"));
        System.out.println(perm2("alphabet"));
    }
}

助手class:

public class CharIndexHolder implements Comparable<CharIndexHolder> {
    public int index;
    private char character;
    public int assignedindex;

    CharIndexHolder(Character character, int index) {
        this.character = character;
        this.index = index;
    }

    @Override
    public int compareTo(CharIndexHolder o) {
        if(this.character < o.character) {
            return -1;
        }
        if(this.character > o.character) {
            return 1;
        }
        if(this.index < o.index) {
            return -1;
        }
        if(this.index > o.index) {
            return 1;
        }
        return 0;
    }       
}

我想不出比 N*log(n) 更快的方法。如果您需要更快的速度,请尝试用长数组替换列表,但每批只分配一次数组(而不是每次调用一次)。

我查看了我以前的解决方案,Arrays.sort() 对于可比数组花费的时间比原始类型数组要长得多。 我尝试了更多方法,以下是为大量单词提供更短时间的方法:

  public static String perm(String word){
    int l = word.length();
    int[] els = new int[l];
    for (int i=0; i<l; i++) {
      els[i] = (word.charAt(i) << 16) | i;
    }
    Arrays.sort(els);
    char[] sb = new char[l];
    for (int i=0; i<els.length; i++) {
      sb[i] = (char)('A' + els[i] & 0xFFFF);
    }
    return String.valueOf(sb);
  }

请注意,该方法隐含假设单词仅使用 UTF-16 编码的低 15 位(对于英文字母表中的单词为真)。

在内存利用率方面,您必须小心 Java 中的测量值。事实上,一种方法与另一种方法相比,内存利用率可能会飙升,这不一定是一个好的指标,因为内存可能会被垃圾收集。这里的所有方法都使用临时 arrays/objects ,在执行 perm() 后可用于垃圾回收(返回的字符串除外)。现在,如果您关心降低内存利用率以减少垃圾收集(从而提高性能),我怀疑最后一种方法应该会产生良好的结果,尽管我还没有测量过。