剑指Offer:字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串“abc”,则打印出由a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。

我们解这题时可以将字符串划分为两部分首字符后面的所有字符

首先求所有可能出现在第一个位置的字符,即把首字符和后面的字符交换。
下图是字符串abc所有字符出现在第一个位置的情形:
剑指Offer:字符串的排列_第1张图片

然后对后面部分的字符串进行第一步操作:
剑指Offer:字符串的排列_第2张图片

很容易想到使用递归去解决这个问题。

代码实现:

//pos:首字符的所在位置
private static void Permutation(char[] chs,int pos){
	if(chs==null){
		return;
	}
	if(pos==chs.length-1){
		System.out.println(chs);
		return;
	}
	for(int i=pos;i<chs.length;i++){
		//首部字符和它后面的字符(包括自己)进行交换
		char temp = chs[i];
		chs[i] = chs[pos];
		chs[pos] = temp;
		//递归求后面的字符的排列
		Permutation(chs,pos+1);
		//由于前面交换了一下,所以chs的内容改变了,我们要还原回来
		temp = chs[i];
		chs[i] = chs[pos];
		chs[pos] = temp;
	}
}

本题拓展:
      如果不是求字符的所有排列,而是求字符的所有组合,应该怎么办呢? 还是输入三个字符 a、b、c,则它们的组合有 a、b、c、ab、ac、be、abc。 当交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是同一个组合。比如 ab 和 ba 是不同的排列,但只算一个组合。

      如果输入 n 个字符,则这 n 个字符能构成长度为 1 的组合、长度为 2 的组合、…、长度为 n 的组合。在求 n 个字符的长度为 m ( 1<=m<=n) 的 组合的时候,我们把这 n 个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取 m-1个字 符:如果组合里不包含第一个字符,则下一步在剩余的 n-1 个字符里选取 m 个字符。也就是说,我们可以把求 n 个字符组成长度为 m 的组合的问题分解成两个子问题,分别求 n-1 个字符串中长度为 m-1 的组合,以及求 n-1 个字符的长度为 m 的组合。这两个子问题都可以用递归的方式解决。

实现代码:

private static void  Combination(char[] chs,int m,int pos,List<Character> list){
	if(chs==null){
		return;
	}
	if(m==0){
		System.out.println(list.toString());
		return;
	}
	if(pos==chs.length){
		return;
	}
	//选择首字符
	list.add(chs[pos]);
	Combination(chs,m-1,pos+1,list);
	//不选择首字符
	list.remove((Character)chs[pos]);
	Combination(chs,m,pos+1,list);
}

测试:

public static void main(String[] args) {
	System.out.print("Please input string:");
	String str = new Scanner(System.in).next();
	char[] chs = str.toCharArray();
	List list = new ArrayList<Character>();
	for(int m=1;m<=chs.length;m++){
		Combination(chs,m,0,list);
	}
}

剑指Offer:字符串的排列_第3张图片

除了这种解法还有一种解法-----位图法。
譬如选择表示为“1”,不选择表示为“0”,那么abc的组合方法有:001(a),010(b),011(ab),100(c),101(ac),110(cb),111(abc)。000是没选择,不行。共有 2 s t r l e n ( " a b c " ) − 1 {2}^{strlen("abc")}-1 2strlen("abc")1中组合。
C语言实现代码,java类似:

#include
#include

void Combination(char *str)
{
	if(str == NULL)
		return ;
	int len = strlen(str);
	int n = 1<<len;//1左移len位,求得的n表示共有几种组合
	int i=1;
	int j=0;
	for(i=1;i<n;i++)    //从 1 循环到 2^len -1
	{
		for(j=0;j<len;j++)
		{
			int temp = i;
			if(temp & (1<<j))   //对应位上为1,则输出对应的字符
			{
				printf("%c",*(str+j));
			}
		}
		printf("\n");
	}
}
void main()
{
	char str[] = "abc";
	Combination(str);
}

你可能感兴趣的:(java,剑指Offer,全排列,剑指Offer,Java实现)