枚举序列中所有语言的单词

时间:2017-11-25 23:47:19

标签: java enumeration

我已成功使用以下方法枚举语言Σ= {a *}和Σ= {a ^ n b ^ n}的所有单词:

public class AStar {
    public static int n = 0;
    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            System.out.println(next());
        }
    }

    public static String next(){
        String as="" , bs="";
        String s= "";
        for(int i=0; i<n; i++) {
            as+="a"; bs+="b";
            s=as+bs;
        }
        n++;
        return s;
    }
}

在每次调用next()时,它会打印一个这样的单词(使用for循环多次调用): ab,aabb,aaabbb,......,a ^ n b ^ n

当前问题

现在我正在研究一个类似的类,可以枚举语言Σ* = {a,b}

在每次调用next()时,它应该返回一个在前面返回的单词之后出现的新单词,例如,它应该返回这些单词:

'','a','b','aa','ab','ba','bb','aaa',......高于有文字的单词

文字的排序并不重要,我已经尝试过这种逻辑但到目前为止没有成功

public class ABStar {
    static int col=0, row=0, cur=0, rlen=0, flag=1, set=0;
    public static void main(String[] args) {
        for(int i=0;i<5;i++){
            System.out.println(next());
        }
    }
    public static String next(){
        String s="";
        row = 1 << col;
        rlen = row/2;
        for(int i=1; i<=row; i++){
            for(int j=1 ; j<=col ; j++){
                if(col==1 && flag ==1){
                    return s+="a";
                }
                else if(col==1 && flag ==2){
                    return s+="b";
                }
                rlen --;
                if(rlen==0){
                    flag = 3-flag;
                    rlen=row/2;
                }
            }
        }
        col++;
        return "";
    }
}

我正在使用标志col(列),行(行),cur(当前),标志(1表示a,2表示b),rlen(每个标志的行长度),我正在使用这些属性保持不同呼叫之间的状态。

我试图用近二十几个逻辑来解决这个问题,但都是徒劳的,请帮我解决这个问题,我将承担很高的责任。

2 个答案:

答案 0 :(得分:1)

两个字母字母的优雅解决方案

由于您的字母表中只有两个字母,优雅的解决方案可能是使用整数的二进制分解(a代表二进制0b代表1 })。以下是您可以实施的算法:

private static final int MAX_LENGTH = 3;

public static void main(String[] args) {
    int wordLength = 1;
    int current = 0;
    int max = (1 << wordLength) - 1;

    while (wordLength <= MAX_LENGTH) {
        System.out.println(makeWord(current, wordLength));

        if (current < max) current++;
        else {
            wordLength++;
            current = 0;
            max = (1 << wordLength) - 1;
        }
    }
}

private static String makeWord(int current, int wordLength) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < wordLength; i++) {
        sb.append((char) ((current % 2) + 'a'));
        current >>= 1;
    }
    return sb.reverse().toString();
}

输出:

a
b
aa
ab
ba
bb
aaa
aab
aba
abb
baa
bab
bba
bbb

任何字母表的一般解决方案

您可以通过计算基数k(其中k是字母表的大小)而非2来概括上述解决方案。它可能如下所示:

public static void main(String[] args) {
    listWords(new char[]{ 'e', 'z', 'f' }, 3);
}

private static void listWords(char[] alphabet, int maxWordLength) {
    Arrays.sort(alphabet);
    int base = alphabet.length;

    int wordLength = 1;
    int current = 0;
    int max = (int) Math.pow(base, wordLength) - 1;

    while (wordLength <= maxWordLength) {
        System.out.println(makeWord(alphabet, current, wordLength));

        if (current < max) current++;
        else {
            wordLength++;
            current = 0;
            max = (int) Math.pow(base, wordLength) - 1;
        }
    }
}

private static String makeWord(char[] alphabet, int current, int wordLength) {
    int base = alphabet.length;

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < wordLength; i++) {
        sb.append(alphabet[current % base]);
        current /= base;
    }
    return sb.reverse().toString();
}

输出:

e
f
z
ee
ef
ez
fe
ff
fz
ze
zf
zz
eee
eef
eez
efe
eff
efz
eze
ezf
ezz
fee
fef
fez
ffe
fff
ffz
fze
fzf
fzz
zee
zef
zez
zfe
zff
zfz
zze
zzf
zzz

请注意,此实现将比前一个实现慢得多,因为与二进制移位相比,除法和Math.pow操作速度较慢。

非算术通用解

基础k中的计数逻辑也可以手动实现。它可能更有效但肯定会花更多的时间和代码。以下是该算法的一般概念:

  • 首先填写最低值的字符串
  • 然后,你增加最后一个字符的值
  • 当您无法再增加时,重置当前位置右侧的所有字符
  • 你增加你的位置,并增加这个位置的值
  • 你重新开始从字符串右边做同样的事情

如果您使用StringBuilder,那么很酷的是,您可以将每次迭代的数组分配次数最小化为一次,因为StringBuilder的每个状态都可以达到一些操作(与字符串的长度成比例)与之前的状态相同。

答案 1 :(得分:0)

通过遵循@Dici的方法,我已经编写了专门解决我问题的代码。

public class SigmaStar {

//max length of word, just to limit the execution
//change it with your own value
private static final int MAX_LENGTH = 4;

public static void main(String[] args) {
    int wordLength = 0;
    int current = 0;
    int max = (1 << wordLength) - 1;

    while (wordLength <= MAX_LENGTH) {
        System.out.println("'"+makeWord(current, wordLength)+"'");

        if (current < max) current++;
        else {
            wordLength++;
            current = 0;
            max = (1 << wordLength) - 1;
        }
    }
}

private static String makeWord(int current, int wordLength) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < wordLength; i++) {
        sb.append((char) ((current % 2) + 'a'));
        current >>= 1;
    }
    return sb.reverse().toString();
}

}