对一道算法题的思考

xshy3412 xshy3412 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
下面要说的这道题是多天前一位网友提问的,当时没仔细考虑。虽然早已经结帖了。但是最终好像大家都没有给出很可行的解决方法。
原问题是“写出用 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
这些字符拼出来的所有长度小于等于12位的文件名(扩展名不用考虑)。”


今天看算法书时,看到递归算法里面有一个应用,是讲“变位字”的。虽然不能直接拿来解决这个问题,但是经本人稍加改动,竟然可以完美解决上面的那个问题。
首先说一下变位字是怎么回事。假设想要列出一个指定单词的所有变位字,也就是列出该词的全排列,它们都是由原来这个单词的字母组成的。我们称这个工作是变位一个单词或称全排列一个单词的字母。用递归的方法来编程实现全排列单词的思路是:
假设这个词有n个字母:1,全排列最右边的n-1个字母。2,轮换所有n个字母。3,重复以上步骤n 次。很显然的递归思想。
轮换的意思是所有字母向左移一位,但是最左边的字母例外,它“轮换”至最右边字母的后边。下面是实现递归得到所有字母排列的
方法:

public static void doAnagram(int newSize)
{
if(newSize == 1) //if innermost,go no further
{
displayWord();//打印出目前字母数组的单词
return;
}
for (int j=0; j<newSize; j++) //for each position
{
doAnagram(newSize - 1); //anagram remaining

rotate(newSize); //rotate word
}
}

上面那个方法还调用了显示方法(显示目前的整个单词),和轮换方法rotate(),可以看出它是在递归的最里层实现打印整个单词的字母序列。既然递归的最里层可以打印整个单词,那么当从最里层返回时,是不是可以显示长度为n-1的单词,也就是说这个长度的单词字母是原单词的一部分,依次类推,每层的递归返回都可以显示更短长度的单词。因此要在上面方法的for循环体中,加入
显示方法,以显示由原单词的字母的一部分组合成的单词。而更进一步,如果想要做到长度小于等于某个数的字母组合,只需要在显示方法中进行显示之前判断一下当前层的深度。于是,这个问题就算完整地解决了。

import java.io.*;

class AnagramApp1
{
static int size;
static int count;
static char[] arrChar = new char[100];


public static void main(String[] args) throws IOException
{
System.out.print("Enter a word:");
String input = getString();
size = input.length();
count = 0;
for (int j=0; j<size; j++)
{
arrChar[j] = input.charAt(j);
}
doAnagram(size);
}

public static void doAnagram(int newSize)
{
if(newSize == 1) //if innermost,go no further
{
displayWord(newSize); //最后一层,输出的是全部字符的可能组合
return;
}
for (int j=0; j<newSize; j++) //for each position
{
doAnagram(newSize - 1); //anagram remaining

displayWord(newSize); //我加的显示语句,用于显示所有长度小于原单词长度的单词

rotate(newSize); //rotate word
}
}


public static void rotate(int newSize)
{
int j;
int position = size - newSize;
char temp = arrChar[position]; //save first letter

for (j=position+1; j<size; j++) //shift others left
{
arrChar[j-1] = arrChar[j];
}
arrChar[j-1] = temp; //put first on right
}

public static void displayWord(int newSize) //经过改造的显示方法,要接收一个参数以判断当前的递归层数
{
if(count < 99)
System.out.print(" ");
if(count < 9)
System.out.print(" ");

if(size-newSize+1 <= 2) //加入的判断,2就表示长度小于等于2的单词打印出来
{
System.out.print(++count + " ");

for(int j=0;j < size-newSize+1; j++)
{
System.out.print(arrChar[j]);
}
}

System.out.print(" ");
System.out.flush();
if(count%6 == 0)
System.out.println("");
}

public static String getString() throws IOException
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
} //end class AnagramApp



以上代码在算法书作者的原代码基础上修改得到,为了测试方便,没有固定原单词,而是在控制台手工输入,也就是说只要输入由字母组成的字符串(当然也可以是“1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz”),就可以按要求打印出所有的字符组合,并且统计字符个数。当然为了便于验证,可以输入短一点的单词试验一下,看是否正确。

以上是本人的一点愚见,有何不妥之处还请大家指出,或者有更好的方法来解决那个问题,不妨可以一起讨论,共同提高。
...全文

相关推荐

评论 61
收藏 已收藏
分享
返回顶部
xshy3412
Java SE 62,620 成员 307,251 内容