我已成功使用以下方法枚举语言Σ= {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(每个标志的行长度),我正在使用这些属性保持不同呼叫之间的状态。
我试图用近二十几个逻辑来解决这个问题,但都是徒劳的,请帮我解决这个问题,我将承担很高的责任。
答案 0 :(得分:1)
由于您的字母表中只有两个字母,优雅的解决方案可能是使用整数的二进制分解(a
代表二进制0
而b
代表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();
}
}